Spring僅僅是提供了對緩存的支持,但它並無任何的緩存功能的實現,spring使用的是第三方的緩存框架來實現緩存的功能。其中,Spring對EHCache提供了很好的支持。html
Spring的緩存機制是基於Spring的AOP,那麼在Spring Cache中應該存在着一個Advice。Spring並非直接使用org.springframework.cache.Cache,spring把Cache對象交給org.springframework.cache.CacheManager來管理。java
主要是經過相似於aop:advice的cache:advice來進行的。在cache命名空間下定義了一個cache:advice元素用來定義一個對於Cache的advice。其須要指定一個cache-manager屬性,默認爲cacheManager。cache:advice下面能夠指定多個cache:caching元素,其有點相似於使用註解時的@Caching註解。cache:caching元素下又能夠指定cache:cacheable、cache:cache-put和cache:cache-evict元素,它們相似於使用註解時的@Cacheable、@CachePut和@CacheEvict。spring
<cache:advice id="cacheAdvice" cache-manager="cacheManager"> <cache:caching cache="users"> <cache:cacheable method="findById" key="#p0"/> <cache:cacheable method="find" key="#user.id"/> <cache:cache-evict method="deleteAll" all-entries="true"/> </cache:caching> </cache:advice>
上面配置定義了一個名爲cacheAdvice的cache:advice,其中指定了將緩存findById方法和find方法到名爲users的緩存中。這裏的方法還可使用通配符「*」,好比「find*」表示任何以「find」開始的方法。數組
有了cache:advice以後,咱們還須要引入aop命名空間,而後經過aop:config指定定義好的cacheAdvice要應用在哪些pointcut上。緩存
<aop:config proxy-target-class="false"> <aop:advisor advice-ref="cacheAdvice" pointcut="execution(* com.xxx.UserService.*(..))"/> </aop:config>
完整的例子:框架
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:cache="http://www.springframework.org/schema/cache" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-3.1.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd "> <context:component-scan base-package="com.sin90lzc" /> <bean id="ehCacheManagerFactory" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" p:configLocation="classpath:ehcache.xml"/> <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager" p:cacheManager-ref="ehCacheManagerFactory"/> <cache:advice id="cacheAdvice" cache-manager="cacheManager"> <cache:caching> <cache:cacheable cache="dao.select" method="select" key="#id" /> <cache:cache-evict cache="dao.select" method="save" key="#obj" /> </cache:caching> </cache:advice> <aop:config> <aop:advisor advice-ref="cacheAdvice" pointcut="execution(* com.sin90lzc.train.spring_cache.simulation.DaoImpl.*(..))"/> </aop:config></beans>
參考:http://www.mincoder.com/article/2096.shtmlide
@Cacheable能夠標記在一個方法上,也能夠標記在一個類上。當標記在一個方法上時表示該方法是支持緩存的,當標記在一個類上時則表示該類全部的方法都是支持緩存的。spa
對於一個支持緩存的方法,Spring會在其被調用後將其返回值緩存起來,以保證下次利用一樣的參數來執行該方法時能夠直接從緩存中獲取結果,而不須要再次執行該方法。Spring在緩存方法的返回值時是以鍵值對進行緩存的,值就是方法的返回結果,至於鍵的話,Spring又支持兩種策略,默認策略和自定義策略,這個稍後會進行說明。須要注意的是當一個支持緩存的方法在對象內部被調用時是不會觸發緩存功能的。@Cacheable能夠指定三個屬性,value、key和condition。code
value屬性是必須指定的,其表示當前方法的返回值是會被緩存在哪一個Cache上的,對應Cache的名稱。其能夠是一個Cache也能夠是多個Cache,當須要指定多個Cache時其是一個數組。component
例如:
@Cacheable("cache1")//Cache是發生在cache1上的 public User find(Integer id) { return null; } @Cacheable({"cache1", "cache2"})//Cache是發生在cache1和cache2上的 public User find(Integer id) { return null; }
自定義策略是指咱們能夠經過Spring的EL表達式來指定咱們的key。這裏的EL表達式可使用方法參數及它們對應的屬性。使用方法參數時咱們能夠直接使用「#參數名」或者「#p參數的索引」。
例如:
@Cacheable(value="users", key="#id") public User find(Integer id) { return null; } @Cacheable(value="users", key="#p0") public User find(Integer id) { return null; } @Cacheable(value="users", key="#user.id") public User find(User user) { return null; } @Cacheable(value="users", key="#p0.id") public User find(User user) { return null; }
除了上述使用方法參數做爲key以外,Spring還爲咱們提供了一個root對象能夠用來生成key。經過該root對象咱們能夠獲取到如下信息。
當咱們要使用root對象的屬性做爲key時咱們也能夠將「#root」省略,由於Spring默認使用的就是root對象的屬性。
例如:
@Cacheable(value={"users", "xxx"}, key="caches[1].name") public User find(User user) { return null; }
有的時候咱們可能並不但願緩存一個方法全部的返回結果。經過condition屬性能夠實現這一功能。condition屬性默認爲空,表示將緩存全部的調用情形。其值是經過SpringEL表達式來指定的,當爲true時表示進行緩存處理;當爲false時表示不進行緩存處理,即每次調用該方法時該方法都會執行一次。以下示例表示只有當user的id爲偶數時纔會進行緩存。
例如:
@Cacheable(value={"users"}, key="#user.id", condition="#user.id%2==0") public User find(User user) { System.out.println("find user by user " + user); return user; }
在支持Spring Cache的環境下,對於使用@Cacheable標註的方法,Spring在每次執行前都會檢查Cache中是否存在相同key的緩存元素,若是存在就再也不執行該方法,而是直接從緩存中獲取結果進行返回,不然纔會執行並將返回結果存入指定的緩存中。
@CachePut也能夠聲明一個方法支持緩存功能。與@Cacheable不一樣的是使用@CachePut標註的方法在執行前不會去檢查緩存中是否存在以前執行過的結果,而是每次都會執行該方法,並將執行結果以鍵值對的形式存入指定的緩存中。
@CachePut也能夠標註在類上和方法上。使用@CachePut時咱們能夠指定的屬性跟@Cacheable是同樣的。
例如:
@CachePut("users")//每次都會執行方法,並將結果存入指定的緩存中 public User find(Integer id) { return null; }
@CacheEvict是用來標註在須要清除緩存元素的方法或類上的。當標記在一個類上時表示其中全部的方法的執行都會觸發緩存的清除操做。@CacheEvict能夠指定的屬性有value、key、condition、allEntries和beforeInvocation。其中value、key和condition的語義與@Cacheable對應的屬性相似。即value表示清除操做是發生在哪些Cache上的(對應Cache的名稱);key表示須要清除的是哪一個key,如未指定則會使用默認策略生成的key;condition表示清除操做發生的條件。下面咱們來介紹一下新出現的兩個屬性allEntries和beforeInvocation。
allEntries是boolean類型,表示是否須要清除緩存中的全部元素。默認爲false,表示不須要。當指定了allEntries爲true時,Spring Cache將忽略指定的key。有的時候咱們須要Cache一下清除全部的元素,這比一個一個清除元素更有效率。
例如:
@CacheEvict(value="users", allEntries=true) public void delete(Integer id) { System.out.println("delete user by id: " + id); }
清除操做默認是在對應方法成功執行以後觸發的,即方法若是由於拋出異常而未能成功返回時也不會觸發清除操做。使用beforeInvocation能夠改變觸發清除操做的時間,當咱們指定該屬性值爲true時,Spring會在調用該方法以前清除緩存中的指定元素。
例如:
@CacheEvict(value="users", beforeInvocation=true) public void delete(Integer id) { System.out.println("delete user by id: " + id); }
其實除了使用@CacheEvict清除緩存元素外,當咱們使用Ehcache做爲實現時,咱們也能夠配置Ehcache自身的清除策略,其是經過Ehcache的配置文件來指定的。
@Caching註解可讓咱們在一個方法或者類上同時指定多個Spring Cache相關的註解。其擁有三個屬性:cacheable、put和evict,分別用於指定@Cacheable、@CachePut和@CacheEvict。
例如:
@Caching(cacheable = @Cacheable("users"), evict = { @CacheEvict("cache2"), @CacheEvict(value = "cache3", allEntries = true) }) public User find(Integer id) { return null; }
<cache:annotation-driven/>有一個cache-manager屬性用來指定當前所使用的CacheManager對應的bean的名稱,默認是cacheManager,因此當咱們的CacheManager的id爲cacheManager時咱們能夠不指定該參數,不然就須要咱們指定了。
<cache:annotation-driven/>還能夠指定一個mode屬性,可選值有proxy和aspectj。默認是使用proxy。當mode爲proxy時,只有緩存方法在外部被調用的時候Spring Cache纔會發生做用,這也就意味着若是一個緩存方法在其聲明對象內部被調用時Spring Cache是不會發生做用的。而mode爲aspectj時就不會有這種問題。另外使用proxy時,只有public方法上的@Cacheable等標註纔會起做用,若是須要非public方法上的方法也可使用Spring Cache時把mode設置爲aspectj。
CacheManager是Spring定義的一個用來管理Cache的接口。Spring自身已經爲咱們提供了兩種CacheManager的實現,一種是基於Java API的ConcurrentMap,另外一種是基於第三方Cache實現——Ehcache,若是咱們須要使用其它類型的緩存時,咱們能夠本身來實現Spring的CacheManager接口或AbstractCacheManager抽象類。
<bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager"> <property name="caches"> <set> <bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="xxx"/> </set> </property> </bean>
上面的配置使用的是一個SimpleCacheManager,其中包含一個名爲「xxx」的ConcurrentMapCache。
若未指定則將按照Ehcache的默認規則取classpath根路徑下的ehcache.xml文件,若該文件也不存在,則獲取Ehcache對應jar包中的ehcache-failsafe.xml文件做爲配置文件。
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:cache="http://www.springframework.org/schema/cache" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-3.1.xsd"> <context:component-scan base-package="com.sin90lzc" /> <!-- 該Bean是一個org.springframework.cache.CacheManager對象 屬性cacheManager是一個net.sf.ehcache.CacheManager對象 --> <bean id="ehCacheManagerFactory" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" p:configLocation="classpath:ehcache.xml"/> <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager" p:cacheManager-ref="ehCacheManagerFactory"/> <cache:annotation-driven /> </beans>
import org.springframework.cache.annotation.CacheEvict;import org.springframework.cache.annotation.Cacheable;import org.springframework.stereotype.Component; @Componentpublic class DaoImpl implements Dao { /** * value定義了緩存區(緩存區的名字),每一個緩存區能夠看做是一個Map對象 * key做爲該方法結果緩存的惟一標識, */ @Cacheable(value = { "dao.select" },key="#id") @Override public Object select(int id) { System.out.println("do in function select()"); return new Object(); } @CacheEvict(value = { "dao.select" }, key="#obj") @Override public void save(Object obj) { System.out.println("do in function save(obj)"); } }