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将切入点表达式和缓存通知关联起来
④设置切面优先级让缓存切面优先级高于事务切面

 

使用Spring提供的缓存抽象机制整合EHCache为项目提供二级缓存的更多相关文章

  1. 7.4mybatis整合ehcache(mybatis无法实现分布式缓存必须和其他缓存框架整合)

    <\mybatis\day02\14查询缓存-二级缓存-整合ehcache.av> mybatis的缓存机制(一级缓存二级缓存和刷新缓存)和mybatis整合ehcache-- 这里有做本 ...

  2. Spring源码-IOC部分-循环依赖-用实例证明去掉二级缓存会出现什么问题【7】

    实验环境:spring-framework-5.0.2.jdk8.gradle4.3.1 Spring源码-IOC部分-容器简介[1] Spring源码-IOC部分-容器初始化过程[2] Spring ...

  3. Hibernate二级缓存简述及基于Spring4,Hibernate5,Ehcache3的二级缓存配置

    Hibernate L2缓存 缓存的分类 L2缓存工作原理 放入二级缓存的数据 Ehcache 依赖 ehcache.xml 常用的memoryStoreEvictionPolicy(缓存算法) eh ...

  4. java框架之SpringBoot(11)-缓存抽象及整合Redis

    Spring缓存抽象 介绍 Spring 从 3.1 版本开始定义了 org.springframework.cache.Cache 和 org.springframework.cache.Cache ...

  5. ssh整合hibernate 使用spring管理hibernate二级缓存,配置hibernate4.0以上二级缓存

    ssh整合hibernate 使用spring管理hibernate二级缓存,配置hibernate4.0以上二级缓存 hibernate  : Hibernate是一个持久层框架,经常访问物理数据库 ...

  6. mybatis的缓存机制(一级缓存二级缓存和刷新缓存)和mybatis整合ehcache

    1.1  什么是查询缓存 mybatis提供查询缓存,用于减轻数据压力,提高数据库性能. mybaits提供一级缓存,和二级缓存. 一级缓存是SqlSession级别的缓存.在操作数据库时需要构造 s ...

  7. Mybatis整合(Redis、Ehcache)实现二级缓存

    目的: Mybatis整合Ehcache实现二级缓存 Mybatis整合Redis实现二级缓存 Mybatis整合ehcache实现二级缓存 ssm中整合ehcache 在POM中导入相关依赖 < ...

  8. Mybatis学习(五)————— 延迟加载和缓存机制(一级二级缓存)

    一.延迟加载 延迟加载就是懒加载,先去查询主表信息,如果用到从表的数据的话,再去查询从表的信息,也就是如果没用到从表的数据的话,就不查询从表的信息.所以这就是突出了懒这个特点.真是懒啊. Mybati ...

  9. Mybatis(五) 延迟加载和缓存机制(一级二级缓存)

    踏踏实实踏踏实实,开开心心,开心是一天不开心也是一天,路漫漫其修远兮. --WH 一.延迟加载 延迟加载就是懒加载,先去查询主表信息,如果用到从表的数据的话,再去查询从表的信息,也就是如果没用到从表的 ...

随机推荐

  1. 添加Nginx为系统服务(设置开机启动)

    在本节中,我们将创建一个脚本,将Nginx守护进程转换为实际的系统服务. 这有两个作用:守护程序可以使用标准命令控制,更重要的是,它可以在系统启动时自动启动,并在系统关闭时停止. System V s ...

  2. OutputStreamWriter与InputStreamReader(转换流)

    import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import jav ...

  3. 【BZOJ4310】跳蚤

    [BZOJ4310]跳蚤 Description 很久很久以前,森林里住着一群跳蚤.一天,跳蚤国王得到了一个神秘的字符串,它想进行研究. 首先,他会把串分成不超过 k 个子串,然后对于每个子串 S,他 ...

  4. Redis后台监控与管理CacheCloud

    CacheCloud环境需求 Java 7 Maven 3 MySQL Redis 3 具体用法可参考:https://cachecloud.github.io 1.下载CacheCloud 官网ht ...

  5. gitlab 使用流程

    gitlab 使用流程 1. 开发人员写代码,开发产品. 2. 测试人员进行测试,如果发现bug, 填写 Issues - List - new issus 3. 开发人员修复bug, 从master ...

  6. Cookie、sessionStorage与localStorage的区别

    (1) sessionStorage 保存数据的方法: SessionStor.setItem(“key”,”value”) 或者写成 sessionStorage.key=”value” 读取数据的 ...

  7. stm32 中断号和中断处理函数建立关系

    转载:https://www.cnblogs.com/heny-hui/p/7130620.html stm32的中断号根据不同内核和型号,st公司给的官方库中对相应的中断号进行了设置,我们用到哪一个 ...

  8. arm那些事

    ARM简介 ARM的商业模式: ARM只负责设计IC,并且出卖自己的设计IP(版权). ARM自己不生产芯片,而是把设计IP授权给其他半导体厂商来生产芯片. 严格地说,ARM并不是一家半导体厂商.   ...

  9. JS-JS代码插入位置

    一.HTML 页面的 <head> 部分中 由于 HTML 文档是由浏览器从上到下依次载入的,将 JavaScript 代码放置于<head></head> 标签之 ...

  10. Python进阶:函数式编程(高阶函数,map,reduce,filter,sorted,返回函数,匿名函数,偏函数)...啊啊啊

    函数式编程 函数是Python内建支持的一种封装,我们通过把大段代码拆成函数,通过一层一层的函数调用,就可以把复杂任务分解成简单的任务,这种分解可以称之为面向过程的程序设计.函数就是面向过程的程序设计 ...