봄 캐시 (소스 코드를 파싱) 평신도의 언어와 통합을 사용하여
개인 개발 환경
자바 환경 : Jdk1.8.0_60
컴파일러 : 인 IntelliJ의 IDEA 2019.1
springCache 공식 문서 : https://docs.spring.io/spring/docs/5.1.9.RELEASE/spring-framework-reference/integration.html#cache
A, 봄 캐시 추상화
사실, 생성 된 배경 SpringCache 배경으로 봄이 다소 유사한 생산. 코드, 객체 생성 및 복잡한 종속성 자바 EE 프레임 워크 비 대한, 비효율적, 낮은 관찰하기 때문에, 스프링 프레임 워크는 기본적으로, 모든 프로젝트는 (더 봄의 포장을 간소화) 자바 배경 봄 또는 SpringBoot에서 분리 될 수 없다 나왔다 . 일반적으로 스프링 프레임 워크에, 당신은 캐시 지원을 완료하는 데 더 편리하고 간단한 방법이 필요하므로 이제 프로젝트에 직면 높은 동시성 문제가 더 캐싱 애플리케이션의 많은 종류도 증가했다.
SpringCache 자체도 완료 특정 캐시 구현을 충족해야 SpringCache를 사용하는 캐싱 시스템의 추상 실현없이 특정 캐시 용량이다.
- 캐시 인터페이스 사양은 어셈블리 캐시, 각종 동작의 세트를 상기 캐시로 정의된다;
- 캐시 인터페이스는 다양한 봄 xxxCache의 구현을 제공 RedisCache, EhCacheCache는 등 ConcurrentMapCache 경우;
둘째, 중요한 메모, 매개 변수
이름 | 설명 |
---|---|
은닉처 | 캐시 인터페이스 정의 캐시 작업. 이 실현 : RedisCache, EhCacheCache, ConcurrentMapCache 등 |
CacheManager | 캐시 관리자는 캐시 (캐시) 구성 요소를 관리 |
@Cacheable | 구성하는 주된 방법은 요청 파라미터 법에 의해 캐싱 될 수있다 |
@CacheEvict | 캐시 비우기 |
@CachePut | 메소드가 호출되어 있는지 확인하고, 그 결과가 캐시 바랍니다. 차이점은 @Cacheable 각 메소드를 호출할지 여부를 일반적으로 업데이트에서 사용 |
@EnableCaching | 열기 주석 기반 캐싱 |
의 KeyGenerator | 키 생성 전략을 때 캐시 데이터 |
직렬화 | 캐시 데이터 값 때 직렬화 전략 |
@CacheConfig | 노트의이 클래스의 통합 캐시 구성 속성 |
@ 캐시 가능 / @ CachePut / @ 주요 매개 변수 CacheEvict
이름 | 설명 |
---|---|
값 | 스프링 구성 파일에 정의 된 캐시 이름은 적어도 하나의 예를 지정해야 @Cacheable (값 = "mycache") 또는 @Cacheable를 (값 = { "cache1", "cache2에"} |
키 | @Cacheable (값 = "testcache"키 = "# 아이디") : 당신이 SpEL을 지정하지 않을 경우 기본 매개 변수는 모든 방법에 따라, 예를 들어 결합되어, 식에 따라 작성 지정하려면 캐시 키는 비어있을 수 있습니다 |
조건 | 버퍼 조건, 비어있을 수 있으며,이 SpEL을 작성, 그것은 단지 캐시 / 캐시 지우기 예 참, 참 또는 거짓 반환 @Cacheable (값 = "testcache"상태 = "#의 userName.length을 ()> 2") |
하지 않는 한 | 네거티브 캐싱. 조건의 결과가 TRUE 인 경우,이 캐시되지 않습니다. @Cacheable (값 = "testcache"않는 = "#의 userName.length ()> 2") |
allEntries (@CacheEvict) | 모든 캐시 내용을 취소할지 여부를 true로 지정하면, 기본값은 false이며, 메소드 호출 즉시 지우기 예를 들어 캐시 : @CachEvict (값 = "testcache", allEntries = TRUE) |
beforeInvocation (@CacheEvict) | 이 실행 방법 전에 비워 여부 방법은 빈 캐시에서 수행되지 않은 경우 당신은 기본적으로 사실이다 지정한 실행 방법은 예외가 발생하면, 그것은 예를 들어 캐시를 삭제하지 않을 경우, 디폴트는 false입니다 @ CachEvict (값 = "testcache", beforeInvocation = TRUE) |
세, SpEL을 컨텍스트 데이터
봄 캐시 SpEL을 우리가 테이블 봄 공식 문서에서 직접 그려, 사용하는 데이터에 대한 몇 가지 컨텍스트를 제공합니다 :
이름 | 위치 | 기술 | 예 |
---|---|---|---|
methodName로 | 루트 개체 | 현재의 방법은 이름이라고합니다 | #의 root.methodname |
방법 | 루트 개체 | 현재 메소드가 호출됩니다 | #의 root.method.name |
목표 | 루트 개체 | 현재 대상 객체 인스턴스라고 | # root.target |
targetClass를 | 루트 개체 | 현재 클래스는 대상 객체라고 | #의 root.targetClass |
인수 | 루트 개체 | 매개 변수 목록은 현재의 방법이라고 | #의 root.args [0] |
캐시 | 루트 개체 | 현재 메서드 호출은 캐시 목록을 사용하여 | root.caches # [0] .name을 |
인수의 이름 | 실행 컨텍스트 | 상기 방법의 파라미터는 findArtisan (장인 장인)와 같은 전류를 호출하고, 파라미터들은 artsian.id 번호에 의해 얻을 수있다 | #의 artsian.id |
결과 | 실행 컨텍스트 | 방법의 실행 후 리턴 값 (판정을 행하는 방법 만 유효 cacheEvict 않는 한 beforeInvocation = 거짓)를 | #결과 |
넷째, 실제
1. 수입 의존도
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
2. 시작 클래스 캐시 코멘트를 열고 @EnableCaching
/**
* 1、开启基于注解的缓存 @EnableCaching
* 2、标注缓存注解即可
* @Cacheable
* @CacheEvict
* @CachePut
*/
@SpringBootApplication
@EnableCaching //开启缓存
public class CacheApplication{
public static void main(String[] args) {
SpringApplication.run(CacheApplication.class, args);
}
}
3. 캐시 @Cacheable
실행중인 프로세스 :
@Cacheable
먼저 자동으로 생성 된 캐시 캐시 구성 요소를 확보 할 경우이 방법을 실행하기 전에, cacheNames / 값 지정된 이름에 따라 획득 한 쿼리 캐시 (캐시 구성 요소)로 이동합니다.
소스 분석 :
public @interface Cacheable {
// cacheNames/value:指定缓存组件的名字;将方法的返回结果放在哪个缓存中,是数组的方式,可以指定多个缓存
@AliasFor("cacheNames")
String[] value() default {};
@AliasFor("value")
String[] cacheNames() default {};
// 缓存数据使用的key;可以用它来指定。默认是使用方法参数的值
String key() default "";
// key的生成器;可以自己指定key的生成器的组件id,key/keyGenerator:二选一使用;
String keyGenerator() default "";
// 指定缓存管理器;或者cacheResolver指定获取解析器 作用得到缓存集合
String cacheManager() default "";
String cacheResolver() default "";
// 条件符合则缓存,编写SpEL:condition = "#a0>1":第一个参数的值大于1的时候才进行缓存
String condition() default "";
// 条件符合则不缓存,编写SpEL:unless = "#a0==2":如果第一个参数的值是2,结果不缓存;
String unless() default "";
// 是否使用异步模式,是否启用异步模式
boolean sync() default false;
}
드릴 비트 :
@Cacheable(value = "emp" ,key = "targetClass + methodName +#p0")
public Employee getEmp(Integer id){
System.out.println("查询"+id+"号员工");
Employee emp = employeeMapper.getEmpById(id);
return emp;
}
단차 구덩이 :
1, 속성이 value/cacheNames
필요하며 네임 스페이스의 조각에 저장된 캐시를 지정합니다.
2、属性key
是使用的spEL表达式
注意
:踩坑,如果你把methodName
换成method
运行会报错,观察它们的返回类型,原因在于methodName
是String
而methoh
是Method
。
Employee
实体类一定要实现序列化public class Employee implements Serializable
,否则会报java.io.NotSerializableException
异常。
4.更新 @CachePut
@CachePut
既调用方法,又更新缓存数据;同步更新缓存。简单来说就是用户修改数据同步更新缓存数据。
源码分析:(皮一下,去事故与@Cacheable相同,不做过多解释了,狗头护体~~~)
public @interface CachePut {
@AliasFor("cacheNames")
String[] value() default {};
@AliasFor("value")
String[] cacheNames() default {};
String key() default "";
String keyGenerator() default "";
String cacheManager() default "";
String cacheResolver() default "";
String condition() default "";
String unless() default "";
}
操练一下:
注意
该注解的value/cahceNames
和 key
必须与要更新的缓存相同,也就是与@Cacheable
相同。
@CachePut(value = "emp" ,key = "#employee.id")
public Employee updateEmp(Employee employee){
System.out.println("updateEmp:"+employee);
employeeMapper.updateEmp(employee);
return employee;
}
5.清除 @CacheEvict
@CachEvict
的作用 主要针对方法配置,能够根据一定的条件对缓存进行清空 。
源码分析:
public @interface CacheEvict {
// 同上同上同上
@AliasFor("cacheNames")
String[] value() default {};
@AliasFor("value")
String[] cacheNames() default {};
String key() default "";
String keyGenerator() default "";
String cacheManager() default "";
String cacheResolver() default "";
String condition() default "";
// 指定清除这个缓存中所有的数据,示例:@CachEvict(value=”emp”,allEntries=true)
boolean allEntries() default false;
/*
* 示例: @CachEvict(value=”emp”,beforeInvocation=true)
* 代表清除缓存操作是在方法运行之前执行,无论方法是否出现异常,缓存都清除
*
* 示例: @CachEvict(value=”emp”,beforeInvocation=false)(默认)
* 缓存的清除是否在方法之前执行 , 默认代表缓存清除操作是在方法执行之后执行;如果出现异常缓存就不会清除
*/
boolean beforeInvocation() default false;
}
操练一下:
//方法调用后清空所有缓存
@CacheEvict(value="accountCache", allEntries=true)
public void deleteEmp() {
employeeMapper.deleteAll();
}
6.组合 @Caching
有时候我们可能组合多个Cache注解使用,此时就需要@Caching组合多个注解标签了。
源码分析:
public @interface Caching {
// 用于指定多个缓存设置操作
Cacheable[] cacheable() default {};
// 用于指定多个缓存更新操作
CachePut[] put() default {};
// 用于指定多个缓存失效操作
CacheEvict[] evict() default {};
}
操练一下
// @Caching 定义复杂的缓存规则
@Caching(
cacheable = {
@Cacheable(value="emp",key = "#lastName")
},
put = {
@CachePut(value="emp",key = "#result.id"),
@CachePut(value="emp",key = "#result.email")
}
)
public Employee getEmpByLastName(String lastName){
return employeeMapper.getEmpByLastName(lastName);
}
7.全局配置 @CacheConfig
当我们需要缓存的地方越来越多,可以使用@CacheConfig(cacheNames = {"emp"})
注解来统一指定value
的值,这时可省略value
,如果你在你的方法依旧写上了value
,那么依然以方法的value
值为准。
源码分析:
public @interface Caching {
// 用于指定多个缓存设置操作
Cacheable[] cacheable() default {};
// 用于指定多个缓存更新操作
CachePut[] put() default {};
// 用于指定多个缓存失效操作
CacheEvict[] evict() default {};
}
操练一下:
@CacheConfig(cacheNames = {"emp"}, /*keyGenerator = "cacheKeyGenerator"*/)
public class EmployeeServiceImpl implements EmployeeService {
@Override
@Cacheable(/*value = ‘emp’*/ key = "targetClass + methodName +#p0")
public Employee getEmp(Integer id){
Employee emp = employeeMapper.getEmpById(id);
return emp;
}
}
8.主键生成策略 keyGenerator
操练一下:
创建CacheConfig配置类
@Configuration
public class CacheConfig {
/**
* 生成缓存主键策略 (方法名+参数)
*
* @return KeyGenerator
*/
@Bean("cacheKeyGenerator")
public KeyGenerator keyGenerator() {
return (target, method, params) -> (method.getName() + " [ " + Arrays.asList(params) + " ]");
}
}
可以在@CacheConfig
指定生成策略,也可以在@Cacheable/@CachePut/@CacheEvict
指定key生成策略
@CacheConfig(cacheNames = {"emp"}, keyGenerator = "cacheKeyGenerator")
public class EmployeeServiceImpl implements EmployeeService {
@Override
@Cacheable(/*value = ‘emp’,keyGenerator = "cacheKeyGenerator"*/)
public Employee getEmp(Integer id){
Employee emp = employeeMapper.getEmpById(id);
return emp;
}
}