spring-ehcache 註解緩存

最原始的進行緩存的方式:spring

最原始的使用緩存的方式是經過一個全局map保存獲取過的數據,下次獲取數據時先從map中提取,若是有就直接返回,若是沒有就從數據庫中去讀取,而後放入map中,固然,在作更新操做時須要同步更新這個map中的數據。這種方式雖然原始,可是在一些簡單的場景下已經夠用了,好比Java的類加載器就是使用的這種方式緩存加載過的class。數據庫

經過ehcache以編程方式使用緩存:編程

跟上面的方式相同,可是緩存經過ehcache去管理,固然比使用map有N多種好處,好比緩存太大了快達到上限以後,將哪一部分緩存清除出去。這種方式徹底是經過代碼的方式使用ehcache緩存,雖然自由,卻也很麻煩;有些好比單純的場景下,不須要如此麻煩,直接經過註解就好了。緩存

之前在Spring項目中要經過註解的方式使用緩存,好比藉助一個jar包:ehcache-spring-annotations.jar,能夠在googlecode上面下載,不過已經好久沒有更新過了。svn

使用ehcache-spring-annotations.jarthis

Spring配置文件:google

Xml代碼 spa

<?xml version= "1.0" encoding = "UTF-8"?>  
<beans xmlns= "http://www.springframework.org/schema/beans"  
      xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance"  
      xmlns:ehcache= "http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring"  
      xsi:schemaLocation= "  
          http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd  
          http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring/ehcache-spring-1.1.xsd">  
   
      <ehcache:annotation-driven cache-manager ="ehcacheManager" />  
      <ehcache:config cache-manager = "ehcacheManager">  
           <ehcache:evict-expired-elements  
               interval= "60" />  
      </ehcache:config >  
      <bean id = "ehcacheManager"  
           class= "org.springframework.cache.ehcache.EhCacheManagerFactoryBean" >  
           <property name = "configLocation" value= "classpath:ehcache.xml" />  
      </bean >  
</beans>  

共有兩個註解:設計

  • @Cacheabele      :指定方法使用緩存
  • @TriggersRemove  :從緩存中移除對象

在查詢的方法上使用緩存:code

Java代碼 

@Cacheable(cacheName="platform.config")  

在刪除或更新的方法上清空緩存:

Java代碼 

@TriggersRemove(cacheName="platform.config", when=When.AFTER_METHOD_INVOCATION , removeAll=true)  
public void updateConfig(SystemConfig config) {  
     this.configDao.update(config);  
}  

 

對於這種方式,這裏不作詳細探討。

在Spring 3.1之前,必須藉助以上jar包才能支持以註解的方式使用緩存,可是從Spring 3.1開始,已經提供了原生的註解支持,固然也更增強大。

Spring 3.1及以上版本的原生註解支持

Spring配置文件:

Xml代碼 

<?xml version= "1.0" encoding = "UTF-8"?>  
<beans xmlns= "http://www.springframework.org/schema/beans"  
      xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance"  
      xmlns:cache= "http://www.springframework.org/schema/cache"  
      xsi:schemaLocation= "  
          http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd  
          http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd">  
   
      <cache:annotation-driven cache-manager ="ehcacheCacheManager" />  
      <bean id = "ehcacheCacheManager" class= "org.springframework.cache.ehcache.EhCacheCacheManager"  
           p:cacheManager-ref= "ehcacheManager" />  
      <bean id = "ehcacheManager"  
           class= "org.springframework.cache.ehcache.EhCacheManagerFactoryBean" >  
           <property name = "configLocation" value= "classpath:ehcache.xml" />  
      </bean>  
</beans>  
 

 

Spring原生的緩存的註解共有四個:

  • @Cacheable  :應用到讀取數據的方法上,便可緩存的方法,如查找方法:先從緩存中讀取,若是沒有再調用方法獲取數據,而後把數據添加到緩存中
  • @CacheEvict :即應用到移除數據的方法上,如刪除方法,調用方法時會從緩存中移除相應的數據
  • @CachePut   :應用到寫數據的方法上,如新增/修改方法,調用方法時會自動把相應的數據放入緩存
  • @Caching    :上面三種註解配置方法時,一個方法只能使用三者之一。若是要使用多個,則須要使用@Caching

 

在查詢的方法上使用緩存:

Java代碼 

@Cacheable(value="platform.config" )  
public String querySingleConfigValue(String configKey) {}

指定key的生成規則:

Java代碼 

@Cacheable(value="platform.config", value="#configKey")  
public String querySingleConfigValue(String configKey) {}

緩存的key的生成:

若是在Cache註解上沒有指定key的話,會使用KeyGenerator生成一個key,默認提供了DefaultKeyGenerator生成器(Spring4以後使用SimpleKeyGenerator)。

若是隻有一個參數,就使用該參數做爲key,不然使用SimpleKey做爲key,好比有兩個入參,那麼key將是這樣的形式:SimpleKey [DEVELOPER_NAME,chenfeng]。

能夠在Cache註解上指定key的生成規則,經過SpEL表達式指定規則。詳細能夠參考:Spring Cache抽象詳解

若是沒有入參,又沒有指定key,那麼key將是「SimpleKey []」,這將很容易形成緩存的混亂,並且也不利於在更新的時候進行緩存的更新或移除。


下面的代碼入參是:SimpleKey []

Java代碼 

 
@Cacheable (value = PlatformPrivateConstants.CACHE_NAME_CONFIG)  
public List<SystemConfig> queryAllSingleConfigs() {  }

下面的代碼入參是:SimpleKey [DEVELOPER_NAME,chenfeng]

Java代碼 

@Cacheable (value = PlatformPrivateConstants.CACHE_NAME_CONFIG )  
public String querySingleConfigValue(String configKey, String defaultValue) {  }

在更新的方法上更新緩存:

Java代碼 

@CachePut(value=PlatformPrivateConstants.CACHE_NAME_CONFIG, key="#config.configKey")  
public SystemConfig updateConfig(SystemConfig config) {  }

 經過"#config.configKey"指定以入參config對象的configKey屬性值做爲緩存的key。

更新的方法必須將要緩存的對象做爲返回值,只有這個返回的對象纔會放入緩存中,若是在返回值被返回以前篡改了其內部數據,也會被反映到緩存中。

指定正確的key以防止緩存混亂:

下面兩個方法,前者經過configKey查詢對象,後者經過configKey查詢對象中的configValue屬性值:

Java代碼 

public SystemConfig querySingleConfig(String configKey) {  
public String querySingleConfigValue(String configKey) {  }

 若是不指定key,或者使用相同的key,好比:Java代碼 

@Cacheable(value="platform.config")  
public SystemConfig querySingleConfig(String configKey) {  }
@Cacheable(value="platform.config")  
public String querySingleConfigValue(String configKey) {  }

若是以"DEVELOPER_NAME"做爲configKey分別調用這兩個方法,那麼,先調用哪一個方法,則那個方法的返回值會以"DEVELOPER_NAME"做爲key存入緩存中,此時調用這兩個方法時都會從緩存中取得這個值。好比先調用了querySingleConfig方法,那麼查詢到的SystemConfig對象就會以"DEVELOPER_NAME"爲key存入緩存中,而後調用querySingleConfigValue方法,由於仍會以"DEVELOPER_NAME"做爲key從緩存中提取數據,這時就會從緩存中取得了剛纔那個SystemConfig對象,卻看成是字符串型的configValue屬性值返回了。

因此必須爲這兩個方法指定不一樣的緩存key:

Java代碼 

@Cacheable(value="platform.config", key = "#configKey.concat('_object'))  
public SystemConfig querySingleConfig(String configKey) {  }
@Cacheable(value="platform.config")  
public String querySingleConfigValue(String configKey) {  }

 

這樣前者使用入參configKey值後接"_object"做爲key,然後者使用入參configKey值爲key,就不會相互覆蓋了。

在更新的方法上同時更新多個緩存:

在查詢時,可能經過id查詢也可能經過name查詢,這樣在緩存中就存有兩份數據,在更新的時候就必須同時更新這兩份緩存。

Java代碼 

@Cacheable(value="platform.config", key = "#configId)  
public SystemConfig querySingleConfig(long configId) { } 
@Cacheable(value="platform.config", key = "#configKey)  
public SystemConfig querySingleConfig(String configKey) {  }

 

經過@Caching註解組合多個@CachePut註解,從而在調用更新方法時同時更新多份緩存(以不一樣的key存在於緩存中)

Java代碼 

@Caching(put={@CachePut(value="platform.config" , key="#config.configId"),  
              @CachePut(value="platform.config" , key="#config.configKey" )})  
public SystemConfig updateConfig(SystemConfig config) {  }

在更新方法上同時更新和清除緩存:

上面的方法雖然能夠同時更新多個緩存,可是必須保證這些緩存的值是徹底同樣的,好比上面兩個方法緩存的都是SystemConfig對象,而對於下面的方法就無能爲力了,由於下面的方法緩存的是SystemConfig對象的configValue屬性值,而上面的方式只能把做爲返回值的SystemConfig對象更新到緩存中。

Java代碼 

@Cacheable(value="platform.config")  
public String querySingleConfigValue(String configKey) {  }

 

對於這種狀況,經過@CacheEvict清除那些沒法更新的緩存,這樣下次獲取不到這些緩存就會越過緩存從數據庫查詢最新的數據。

Java代碼 

@Caching(evict={@CacheEvict(value="platform.config", key="#config.configKey" )},  
         put={@CachePut(value="platform.config", key="#config.configId.concat('_object')"),  
              @CachePut(value="platform.config", key="#config.configKey.concat('_object')" )})  
public SystemConfig updateConfig(SystemConfig config) {  }

使用緩存的業務層的設計宗旨:

使用緩存的業務類應儘可能精簡、方法應儘量少,只保留最緊要的方法。

由於進行更新操做時須要考慮每個的獲取數據的方法,必須將可能被更新操做波及的全部緩存進行更新或清除,若是獲取數據的方法過多,這個工做量將變得很大,而且很容易出錯,好比忘記了更新或清除某一份緩存,而大型項目中這種錯誤可能難以被發現。另外,保存多份緩存,也增長了ehcache的負擔,由於它須要維護這些緩存數據,好比須要判斷哪些緩存最久未使用而從緩存中移除等。

因此應該在處於低層的業務類上使用緩存,而在高層的業務類上提供豐富的獲取數據的方法,高層業務類全部操做均調用底層的業務類實現。

對於不會被頻繁調用的方法,不要進行緩存,沒有實際意義,還無謂增大ehcache的負擔,而且浪費寶貴的內存。

相關文章
相關標籤/搜索