码迷,mamicode.com
首页 > 编程语言 > 详细

Spring(八):缓存

时间:2015-09-23 15:11:27      阅读:276      评论:0      收藏:0      [点我收藏+]

标签:

    Spring仅仅是提供了对缓存的支持,但它并没有任何的缓存功能的实现,spring使用的是第三方的缓存框架来实现缓存的功能。其中,Spring对EHCache提供了很好的支持。

    Spring的缓存机制是基于Spring的AOP,那么在Spring Cache中应该存在着一个Advice。Spring并不是直接使用org.springframework.cache.Cache,spring把Cache对象交给org.springframework.cache.CacheManager来管理。


1、基于xml配置缓存

    主要是通过类似于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。

<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>


2、注解驱动的缓存配置

参考:http://www.mincoder.com/article/2096.shtml

2.1、@Cacheable

    @Cacheable可以标记在一个方法上,也可以标记在一个类上。当标记在一个方法上时表示该方法是支持缓存的,当标记在一个类上时则表示该类所有的方法都是支持缓存的。

    对于一个支持缓存的方法,Spring会在其被调用后将其返回值缓存起来,以保证下次利用同样的参数来执行该方法时可以直接从缓存中获取结果,而不需要再次执行该方法。Spring在缓存方法的返回值时是以键值对进行缓存的,值就是方法的返回结果,至于键的话,Spring又支持两种策略,默认策略和自定义策略,这个稍后会进行说明。需要注意的是当一个支持缓存的方法在对象内部被调用时是不会触发缓存功能的。@Cacheable可以指定三个属性,value、key和condition。

2.1.1、 value属性指定Cache名称

       value属性是必须指定的,其表示当前方法的返回值是会被缓存在哪个Cache上的,对应Cache的名称。其可以是一个Cache也可以是多个Cache,当需要指定多个Cache时其是一个数组。

例如:

@Cacheable("cache1")//Cache是发生在cache1上的
   public User find(Integer id) {
      return null;
   }

@Cacheable({"cache1", "cache2"})//Cache是发生在cache1和cache2上的
   public User find(Integer id) {
      return null;
   }
2.1.2、使用key属性自定义key

    自定义策略是指我们可以通过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;
   }
2.1.3、condition属性指定发生的条件

    有的时候我们可能并不希望缓存一个方法所有的返回结果。通过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;
   }


2.2、@CachePut

    在支持Spring Cache的环境下,对于使用@Cacheable标注的方法,Spring在每次执行前都会检查Cache中是否存在相同key的缓存元素,如果存在就不再执行该方法,而是直接从缓存中获取结果进行返回,否则才会执行并将返回结果存入指定的缓存中。

    @CachePut也可以声明一个方法支持缓存功能。与@Cacheable不同的是使用@CachePut标注的方法在执行前不会去检查缓存中是否存在之前执行过的结果,而是每次都会执行该方法,并将执行结果以键值对的形式存入指定的缓存中。

    @CachePut也可以标注在类上和方法上。使用@CachePut时我们可以指定的属性跟@Cacheable是一样的。

例如:

@CachePut("users")//每次都会执行方法,并将结果存入指定的缓存中
   public User find(Integer id) {
      return null;
   }


2.3、@CacheEvict

    @CacheEvict是用来标注在需要清除缓存元素的方法或类上的。当标记在一个类上时表示其中所有的方法的执行都会触发缓存的清除操作。@CacheEvict可以指定的属性有value、key、condition、allEntries和beforeInvocation。其中value、key和condition的语义与@Cacheable对应的属性类似。即value表示清除操作是发生在哪些Cache上的(对应Cache的名称);key表示需要清除的是哪个key,如未指定则会使用默认策略生成的key;condition表示清除操作发生的条件。下面我们来介绍一下新出现的两个属性allEntries和beforeInvocation。

2.3.1、allEntries属性

    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);
   }
2.3.2、beforeInvocation属性

    清除操作默认是在对应方法成功执行之后触发的,即方法如果因为抛出异常而未能成功返回时也不会触发清除操作。使用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的配置文件来指定的。


2.4、@Caching

    @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;
   }


2.5、<cache:annotation-driven>

    <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。


3、配置CacheManager

    CacheManager是Spring定义的一个用来管理Cache的接口。Spring自身已经为我们提供了两种CacheManager的实现,一种是基于Java API的ConcurrentMap,另一种是基于第三方Cache实现——Ehcache,如果我们需要使用其它类型的缓存时,我们可以自己来实现Spring的CacheManager接口或AbstractCacheManager抽象类。

3.1、基于ConcurrentMap的配置

<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。

3.2、基于Ehcache的配置

    若未指定则将按照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)");
    }

}


Spring(八):缓存

标签:

原文地址:http://my.oschina.net/u/1020238/blog/510069

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!