介绍SpringBoot项目中使用缓存,以前先介绍一下Spring的缓存抽象和JSR107,本博客是我在学习尚硅谷视频和参考其它博客以后作的笔记,仅供学习参考java
@git
Spring从3.1开始定义了org.springframework.cache.Cache
和org.springframework.cache.CacheManager接口来统一不一样的缓存技术;并支持使用Java Caching(JSR-107)注解简化咱们进行缓存开发。Spring Cache 只负责维护抽象层,具体的实现由你的技术选型来决定。将缓存处理和缓存技术解除耦合。github
Java Caching(JSR-107)定义了5个核心接口,分别是CachingProvider, CacheManager, Cache, Entry和 Expiry。redis
引用尚硅谷视频课件中的图示:
spring
例子实践以前,先简单介绍Spring提供的重要缓存注解sql
ok,本博客以尚硅谷视频例子进行改写,用这个比较经典的例子进行说明apache
环境准备:api
DROP TABLE IF EXISTS `employee`; CREATE TABLE `employee` ( `id` int(11) NOT NULL AUTO_INCREMENT, `lastName` varchar(255) DEFAULT NULL, `email` varchar(255) DEFAULT NULL, `gender` int(2) DEFAULT NULL, `d_id` int(11) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `department`; CREATE TABLE `department` ( `id` int(11) NOT NULL AUTO_INCREMENT, `departmentName` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> </dependency>
@EnableCaching开启基于注解的缓存数组
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCaching; @SpringBootApplication @EnableCaching public class SpringbootCacheApplication { public static void main(String[] args) { SpringApplication.run(SpringbootCacheApplication.class, args); } }
@Cacheable注解的做用,前面也简介了,主要是针对方法配置,可以根据方法的请求参数对其结果进行缓存,介绍一下注解的主要属性缓存
@Cacheable(value = {"emp"}, /*keyGenerator = "myKeyGenerator",*/key = "#id",condition = "#a0>=1",unless = "#a0!=2") public Employee getEmp(Integer id) { Employee employee = this.employeeMapper.getEmpById(id); LOG.info("查询{}号员工数据",id); return employee; }
这里也可使用自定义的keyGenerator,使用属性keyGenerator = "myKeyGenerator
定义一个@Bean类,将KeyGenerator添加到Spring容器
@Configuration public class CacheConfig { @Bean(value = {"myKeyGenerator"}) public KeyGenerator keyGenerator(){ return new KeyGenerator() { @Override public Object generate(Object target, Method method, Object... params) { return method.getName()+"["+ Arrays.asList(params).toString()+"]"; } }; } }
@CachePut注解也是一个用来缓存的注解,不过缓存和@Cacheable有明显的区别是即调用方法,又更新缓存数据,也就是执行方法操做以后再来同步更新缓存,因此这个主键经常使用于更新操做,也能够用于查询,主键属性和@Cacheable有不少相似的,详情参看@link @CachePut源码
/** * @CachePut:既调用方法,又更新缓存数据;同步更新缓存 * 修改了数据,同时更新缓存 */ @CachePut(value = {"emp"}, key = "#result.id") public Employee updateEmp(Employee employee){ employeeMapper.updateEmp(employee); LOG.info("更新{}号员工数据",employee.getId()); return employee; }
主要属性:
@CacheEvict(value = {"emp"}, beforeInvocation = true,key="#id") public void deleteEmp(Integer id){ employeeMapper.deleteEmpById(id); //int i = 10/0; }
@Caching 用于定义复杂的缓存规则,能够集成@Cacheable和 @CachePut
// @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); }
@CacheConfig注解能够用于抽取缓存的公共配置,而后在类加上就能够,eg:@CacheConfig(cacheNames = {"emp"},cacheManager = "employeeCacheManager")
附录拓展:SpEL表达式用法
Cache SpEL available metadata
名称 | 位置 | 描述 | 示例 |
---|---|---|---|
methodName | root对象 | 当前被调用的方法名 | #root.methodname |
method | root对象 | 当前被调用的方法 | #root.method.name |
target | root对象 | 当前被调用的目标对象实例 | #root.target |
targetClass | root对象 | 当前被调用的目标对象的类 | #root.targetClass |
args | root对象 | 当前被调用的方法的参数列表 | #root.args[0] |
caches | root对象 | 当前方法调用使用的缓存列表 | #root.caches[0].name |
argument Name | 执行上下文(avaluation context) | 当前被调用的方法的参数,如findArtisan(Artisan artisan),能够经过#artsian.id得到参数 | #artsian.id |
result | 执行上下文(evaluation context) | 方法执行后的返回值(仅当方法执行后的判断有效,如 unless cacheEvict的beforeInvocation=false) | #result |
基于前面的Spring缓存环境,集成redis要引入相关配置:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> </dependency>
切换缓存方式为Redis:spring.cache.type=redis
RedisTemplate配置
@Resource private LettuceConnectionFactory lettuceConnectionFactory; @Bean @Primary public RedisTemplate<Object,Object> redisTemplate(){ RedisTemplate<Object,Object> redisTemplate = new RedisTemplate<Object, Object>(); redisTemplate.setConnectionFactory(lettuceConnectionFactory); Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = this.initJacksonSerializer(); // 设置value的序列化规则和 key的序列化规则 redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.afterPropertiesSet(); return redisTemplate; }
RedisCacheManager相关代码能够参考博文,该博主已经对代码作了比较好的封装,因此本文不复制代码
使用RestTemplate操做redis
@Autowired DepartmentMapper departmentMapper; @Qualifier("redisCacheManager") @Autowired RedisCacheManager redisCacheManager; // @Cacheable(cacheNames = "dept",cacheManager = "redisCacheManager") // public Department getDeptById(Integer id){ // System.out.println("查询部门"+id); // Department department = departmentMapper.getDeptById(id); // return department; // } // 使用缓存管理器获得缓存,进行api调用 public Department getDeptById(Integer id){ LOG.info("查询id为{}的员工信息",id); //获取某个缓存 Cache deptCache = redisCacheManager.getCache("dept"); Department department = null; if(deptCache.get(id)==null){ department = departmentMapper.getDeptById(id); deptCache.put(id,department); } else { SimpleValueWrapper valueWrapper = (SimpleValueWrapper) deptCache.get(id); department = (Department)valueWrapper.get(); } return department; }
固然使用前面的Spring主键也是能够缓存的,
参考博文:
缓存抽象层Spring cache实战操做
代码例子下载:github连接