使用Spring提供的缓存抽象机制整合EHCache为项目提供二级缓存

 

Spring自身并没有实现缓存解决方案,但是对缓存管理功能提供了声明式的支持,能够与多种流行的缓存实现进行集成。

Spring Cache是作用在方法上的(不能理解为只注解在方法上),其核心思想是:当我们在调用一个缓存方法时会把该方法参数和返回结果作为一个键值存放在缓存中,等到下次利用同样的参数调用该方法时将不再执行该方法,而是直接从缓存中获取结果进行返回。所以在使用Spring Cache的时候我们要保证我们的缓存的方法对于相同的方法参数要有相同的返回结果

 
1.适合和不适合保存到二级缓存的数据

①适合

[1]经常被查询,很少或几乎不修改的
[2]不是特别重要,允许出现偶尔的并发问题
[3]不会被其他应用程序修改的

②不适合

[1]经常被修改
[2]特别重要,不允许出现任何的并发问题,例如:财务数据
[3]有可能被其他应用程序修改
2.Survey项目中适合存入二级缓存的数据
①验证权限时查询的Res对象
Res getResByServletPath(String servletPath);
②参与调查相关方法
EngageService.PageInfo<Survey> getSurveyPage(Integer userId, boolean completed, Integer pageNum);
EngageService.Survey getSurveyDeeply(Integer surveyId);
3.使用Spring提供的缓存抽象机制整合EHCache
①用伪代码展示缓存切面的工作原理
try {
    //1.尝试从缓存中获取数据
    Object value = cacheMap.get(key);
    
    //2.判断value是否为null
    if(value == null){
        //3.实际执行目标方法
        value = 目标对象.目标方法();
        
        //4.将目标方法执行结果存入缓存
        cacheMap.put(key,value);
    }
    
    //5.返回value
    return value;
}catch(Exceptin e){
}
②Spring缓存抽象使用时的注意事项
[1]如果一个方法在输入相同的情况下输出不一定相同,那么不能使用该机制。
int count = userService.getRegistUserCount(boolean active);
[2]目标方法必须每一次都实际被调用,那么不能使用该机制使用了缓存抽象机制后目标方法理论上只会被执行一次
 

 Cache Abstraction

4.使用步骤
①创建键生成器类,实现org.springframework.cache.interceptor.KeyGenerator接口
 
  
public class UserKeyGenerator implements KeyGenerator {
   //命名方式:类名.方法名.参数名。。。
    @Override
    public Object generate(Object target, Method method, Object... params) {
        //target:目标对象
        //method:目标方法
        //params:实参数组
        StringBuilder bulider = new StringBuilder();
        //获取目标对象名字
        String name = target.getClass().getName();
        bulider.append(".").append(name);
        //获取方法的名字
        String methodName = method.getName();
        bulider.append(".").append(methodName);
        //获取所有的参数
        if(params!=null && params.length!=0){
            for (int i = 0; i < params.length; i++) {
                //    Object object = params[i];
                bulider.append(".").append(params[i]);
            }
        } 
        String key = bulider.substring(1);
        System.out.println(key);
        return key;
    }

}

2)需要在Spring配置文件中配置对应的bean

   <bean id="userKeyGenerator" class="com.lamsey.survey.Ehcache.UserKeyGenerator"/>
 
②引入EHCache环境
[1]加入jar包
[2]引入EHCache自身的配置文件,同时创建一个具名的缓存区域
  不要使用3.0以上的

<!-- Ehcache依赖 -->
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>2.10.3</version>
</dependency>
</dependencies>

③在Spring配置文件中配置缓存抽象对EHCache的整合
         <!-- spring 整合ehcache -->
     <!-- 自定义key生成器 -->
     <bean id="userKeyGenerator" class="com.lamsey.survey.Ehcache.UserKeyGenerator"/>
     <!-- 配置 EhCacheManagerFactoryBean工厂-->
     <bean id="ehCacheManagerFactoryBean" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" >
        <property name="configLocation" value="classpath:ehcache.xml"></property>
    </bean>
    <!-- 配置EhCacheCacheManager -->
    <bean id="ehCacheCacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager" >
        <property name="cacheManager" ref="ehCacheManagerFactoryBean"></property>
    </bean>
    <!--切面及切面表达式配置  -->
    <aop:config>
        <!-- 利用切面表达式找到切面切入点,进行切面编程 -->
         <aop:pointcut expression="execution(* *..ResService.getResByServletPath(String)) 
                     or execution(* *..AnswerService.getSurveyPage(Integer, boolean, Integer)) 
                     or execution(* *..AnswerService.getSurveyDeeply(Integer)) 
                     or execution(* *..SurveyService.completedSurvey(Integer))" id="cachePointCut" />
         <!-- 承上启下,得到切入点,同时连接处理的方法。对切入点进行处理(cache) -->
     <!-- 缓存切面优先级高于数据库事务切面优先级 -->
<aop:advisor advice-ref="cacheAdvice" pointcut-ref="cachePointCut" order="1"/> </aop:config> <!-- 对切入点进行处理,这里表现为缓存 --> <!-- 这里的自定义key【className.method.param1..paramn】 --> <cache:advice id="cacheAdvice" cache-manager="ehCacheCacheManager" key-generator="userKeyGenerator"> <!-- 在cache属性中指定缓存区域的名称 --> <!-- 指定要使用缓存的具体方法,要求必须是缓存切入点覆盖范围内的方法 --> <cache:caching cache="surveyCache"> <cache:cacheable method=" getResByServletPath" /> <cache:cacheable method="getSurveyDeeply"/> </cache:caching> <!-- 使用另外一个有可能被清空数据的缓存区域 --> <cache:caching cache="surveyCacheEvicable"> <cache:cacheable method="getSurveyPage" /> <!-- 执行updateSurveyCompleted方法时清空当前缓存区域 --> <!-- 因为调查有可能更新,当更新后就需要进行重新获取参与调查 ,所以清空该缓存--> <cache:cache-evict method="completedSurvey" all-entries="true" /> </cache:caching> </cache:advice>

ehcache.xml(从hibernate复制出来) 

<ehcache>

    <!-- Sets the path to the directory where cache .data files are created.

         If the path is a Java System Property it is replaced by
         its value in the running VM.

         The following properties are translated:
         user.home - User's home directory
         user.dir - User's current working directory
         java.io.tmpdir - Default temp file path -->
     <!-- 默认以内存作为缓存,但如果不够,在这里设置一个电脑目录存储 -->
    <diskStore path="java.io.tmpdir"/>


    <!--Default Cache configuration. These will applied to caches programmatically created through
        the CacheManager.

        The following attributes are required for defaultCache:

        maxInMemory       - Sets the maximum number of objects that will be created in memory
        eternal           - Sets whether elements are eternal. If eternal,  timeouts are ignored and the element
                            is never expired.
        timeToIdleSeconds - Sets the time to idle for an element before it expires. Is only used
                            if the element is not eternal. Idle time is now - last accessed time
        timeToLiveSeconds - Sets the time to live for an element before it expires. Is only used
                            if the element is not eternal. TTL is now - creation time
        overflowToDisk    - Sets whether elements can overflow to disk when the in-memory cache
                            has reached the maxInMemory limit.

        -->
    <defaultCache
        maxElementsInMemory="10000"
        eternal="false"
        timeToIdleSeconds="120"
        timeToLiveSeconds="120"
        overflowToDisk="true"
        />

    <!--Predefined caches.  Add your cache configuration settings here.
        If you do not have a configuration for your cache a WARNING will be issued when the
        CacheManager starts

        The following attributes are required for defaultCache:

        name              - Sets the name of the cache. This is used to identify the cache. It must be unique.
        maxInMemory       - Sets the maximum number of objects that will be created in memory
        eternal           - Sets whether elements are eternal. If eternal,  timeouts are ignored and the element
                            is never expired.
        timeToIdleSeconds - Sets the time to idle for an element before it expires. Is only used
                            if the element is not eternal. Idle time is now - last accessed time
        timeToLiveSeconds - Sets the time to live for an element before it expires. Is only used
                            if the element is not eternal. TTL is now - creation time
        overflowToDisk    - Sets whether elements can overflow to disk when the in-memory cache
                            has reached the maxInMemory limit.

        -->

    <!-- Sample cache named sampleCache1
        This cache contains a maximum in memory of 10000 elements, and will expire
        an element if it is idle for more than 5 minutes and lives for more than
        10 minutes.

        If there are more than 10000 elements it will overflow to the
        disk cache, which in this configuration will go to wherever java.io.tmp is
        defined on your system. On a standard Linux system this will be /tmp"
        -->
    <cache name="surveyCache"
        maxElementsInMemory="10000"
        eternal="false"
        timeToIdleSeconds="300"
        timeToLiveSeconds="600"
        overflowToDisk="true"
        />

    <!-- Sample cache named sampleCache2
        This cache contains 1000 elements. Elements will always be held in memory.
        They are not expired. -->
    <cache name="surveyCacheEvicable"
        maxElementsInMemory="1000"
        eternal="true"
        timeToIdleSeconds="0"
        timeToLiveSeconds="0"
        overflowToDisk="false"
        /> -->

    <!-- Place configuration for your caches following -->

</ehcache>

 <!-- 缓存切面优先级高于数据库事务切面优先级 -->

   

缓存切面在外层,事务切面在内层
 
结论:为了减少不必要的事务操作让缓存切面的优先级高于事务切面的优先级。
 
 
流程总结
   
 

7.配置二级缓存
①创建键生成器,实现KeyGenerator接口
②引入EHCache环境
[1]引入EHCache依赖
[2]引入EHCache自身配置文件
[3]在EHCache中创建两个具名的缓存区域
(1)不清空的
(2)可清空的
③在Spring配置文件中配置缓存抽象和EHCache的整合
[1]配置缓存管理器工厂
[2]配置缓存管理器
[3]配置缓存切面的切入点表达式
execution(* *..ResService.getResByServletPath(String)) or
execution(* *..EngageService.getSurveyPage(..)) or
execution(* *..EngageService.getSurveyDeeply(..)) or
execution(* *..SurveyService.updateSurveyCompleted(..))
[4]配置缓存切面的通知:装配缓存管理器、装配键生成器、指定id
引用具体的缓存区域
用cache:cacheable标签指定要缓存数据的方法
用cache:cache-evict标签指定导致缓存清空的方法
[5]用aop:advisor将切入点表达式和缓存通知关联起来
④设置切面优先级让缓存切面优先级高于事务切面

 
原文地址:https://www.cnblogs.com/limingxian537423/p/7531649.html