JSR简介源码剖析
总结

JSR简介

JSR 全称为 Java Specification Requests

springboot 自定义jarlancher设置jar顺序_java

Spring生态从3.1开始支持使用Java Caching(JSR-107)注解来简化开发
介绍Spring提供的概念和注解

springboot 自定义jarlancher设置jar顺序_条件判断_02

简单使用

启动类开启缓存支持

//开启缓存支持
@EnableCaching
public class SpringCacheApplication {
   public static void main(String[] args) {
       SpringApplication.run(SpringCacheApplication.class, args);
   }
}

service 标注@Cacheable

/*
    * @Cacheable: 缓存查询:会将被该注解标注的方法的返回值存到缓存中
    *      value/cacheNames: 指定缓存的名称,cacheManager 是管理多个 cache ,以名称进行区分
    *      key: 缓存数据时指定的key值(key,value),默认是该方法的参数值,也可以使用spEL来计算key的值
    *      keyGenerator: key的生成策略,和 key. 进行二选一;自定义keyGenerator
    *      cacheMenager: 指定缓存管理器 redis:employee   ehcache:employee
    *      cacheResolver: 功能和cacheMenager相同,二选一即可
    *      condition: 条件判断:满足这个条件后才会进行缓存
    *      unless: 否定条件:满足这个条件后,不进行缓存
    *      sync: 是否使用异步模式进行缓存 true
    *          1.condition/unless 同时满足时,不进行缓存
    *          2.sync值为true时,unless不被支持
    */
   @Cacheable(value = {"employee"}, key = "#id",condition = "#id > 0",unless = "#result == null")
   @Override
   public Employee findEmployeeById(Integer id) {
       return employeeMapper.selectByPrimaryKey(id);
   }

其他注解使用
/*
	 * 更新缓存注解
	 * value -> 指定需要更新的缓存名称
	 * key -> 指定需要更新的缓存key
	 * ★★★ 切记此处一定将实体进行返回,否侧再次根据该id调用查询时会返回为null,或者再次根据该id执行更新时会报错
	 */
	@CachePut(value = {"emp"}, key = "#employee.id")
	public Employee updateEmployee(Employee employee) {
		employeeMapper.updateByPrimaryKeySelective(employee);
		return employee;
	}
/*
	 * 删除缓存注解
	 * value -> 指定需要删除的缓存名称
	 * key -> 指定需要删除的缓存key
	 * allEntries -> 是否清楚指定缓存中的所有键值对,默认为false ,与key 二选一
	 * beforeInvocation -> 在被标注的方法前执行还是后执行 默认为false -> 即在方法执行后执行,但是如果在delete后出现异常,
	 * 					   缓存清除将不起作用.可将值修改为true -> 即方法执行前先清除缓存
	 */
	@CacheEvict(value = {"emp"}, key = "#id")
	public void deleteEmployee(Integer id) {
		employeeMapper.deleteByPrimaryKey(id);
	}
@Service
/*
 * 被@CacheConfig 标注后该类中所有方法的缓存名称将统一为 emp
 * 方法上的 cacheNames 和 value 同样效果
 * 但是在 @CacheConfig 中只能使用 cacheNames
 */
@CacheConfig(cacheNames = {"emp"})
public class EmployeeServiceImpl implements EmployeeService {

	@Autowired
	private EmployeeMapper employeeMapper;

	@Override
	@Cacheable(key = "#id", condition = "#id > 0", unless = "#result == null")
	public Employee findEmployeeById(Integer id) {
		return employeeMapper.selectByPrimaryKey(id);
	}

	@Override
	/*
	 * 更新缓存注解
	 * value -> 指定需要更新的缓存名称
	 * key -> 指定需要更新的缓存key
	 * ★★★ 切记此处一定将实体进行返回,否侧再次根据该id调用查询时会返回为null,或者再次根据该id执行更新时会报错
	 */
	@CachePut(key = "#employee.id")
	public Employee updateEmployee(Employee employee) {
		employeeMapper.updateByPrimaryKeySelective(employee);
		return employee;
	}

	@Override
	/*
	 * 删除缓存注解
	 * value -> 指定需要删除的缓存名称
	 * key -> 指定需要删除的缓存key
	 * allEntries -> 是否清楚指定缓存中的所有键值对,默认为false ,与key 二选一
	 * beforeInvocation -> 在被标注的方法前执行还是后执行 默认为false -> 即在方法执行后执行,但是如果在delete后出现异常,
	 * 					   缓存清除将不起作用.可将值修改为true -> 即方法执行前先清除缓存
	 */
	@CacheEvict(key = "#id")
	public void deleteEmployee(Integer id) {
		employeeMapper.deleteByPrimaryKey(id);
	}
}



源码分析

直接从启动项的 @SpringBootApplication 注解进入,在图中打下断点.

//进入流程
@SpringBootApplication -> @EnableAutoConfiguration -> AutoConfigurationImportSelector.class

springboot 自定义jarlancher设置jar顺序_ide_03


双击shift并进入

springboot 自定义jarlancher设置jar顺序_缓存_04


进入该类中

springboot 自定义jarlancher设置jar顺序_spring_05


所有的缓存类型

springboot 自定义jarlancher设置jar顺序_ide_06


返回的是所有的缓存组件类及加载顺序

springboot 自定义jarlancher设置jar顺序_缓存_07

当项目没有额外导入缓存的相关jar时,默认使用的是 SimpleCacheConfiguration

可以随便打开一个缓存组件类,可以看出条件判断注解必须有RedisConnectionFactory.class才能加载Redis缓存组件类

springboot 自定义jarlancher设置jar顺序_java_08


只有SimpleCacheConfiguration才能创建

springboot 自定义jarlancher设置jar顺序_java_09


此时返回的是一个ConcurrentMapCacheManager,进入该类在getCache()处打下断点,debug放行,此时断点不卡住,项目启动完成,接下来发起请求.

springboot 自定义jarlancher设置jar顺序_spring_10


springboot 自定义jarlancher设置jar顺序_条件判断_11


首次执行cache为空

springboot 自定义jarlancher设置jar顺序_java_12


加锁并进行二次判断,继续为空,创建ConcurrentMapCache并put到map中,供下次调用是使用

springboot 自定义jarlancher设置jar顺序_ide_13


此时进入 Cache 接口的实现类中 -> ConcurrentHashMap

springboot 自定义jarlancher设置jar顺序_条件判断_14


springboot 自定义jarlancher设置jar顺序_缓存_15


在lookup()出打断点,通过表达式可以看出此时为null

springboot 自定义jarlancher设置jar顺序_条件判断_16


断点继续放在put()上并继续执行,此时到DB中进行了首次查询,并将结果put()到当前缓存中

springboot 自定义jarlancher设置jar顺序_ide_17


此时,首次查询结束,清空控制台并再次发起请求

此时可以看到通过’employee’的值取到了缓存,继续执行

springboot 自定义jarlancher设置jar顺序_spring_18


再次执行lookup()方法,此时通过key获取到了缓存值,程序放行,直接返回

springboot 自定义jarlancher设置jar顺序_java_19


执行完毕,控制台没有任何sql输出

springboot 自定义jarlancher设置jar顺序_spring_20


关于SimpleKey的生成策略,可以查看 SimpleKeyGenerator 类

springboot 自定义jarlancher设置jar顺序_spring_21


springboot 自定义jarlancher设置jar顺序_缓存_22

总结

1.启动时默认使用 SimpleCacheConfiguration 组件类,并创建 ConcurrentMapCacheManager 对象存到容器中
2.底层数据结构为 ConcurrentHashMap 以key,value的形式存放缓存数据
3.整体执行流程:
1)通过指定的名字到CacheManager中获取相应的缓存,首次没有会进行相应的创建
2)去cache中查找缓存,无参数请求时默认的key为new SimpleKey(),单个参数时为该参数值,多个参数时对应调用SimpleKey相应的有参构造
3)没有查到缓存调用目标方法继续执行,从DB中查询数据
4)将数据put到当前缓存中


end