Springboot中缓存的工作原理
要想在springboot中使用缓存,首先要了解springboot中缓存的工作原理。
我们知道springboot在启动时会有很多的自动配置类(xxx-Autoconfiguration类),当我们要使用缓存时,首先缓存的自动配置类会生效。
1.找到CacheAutoConfiguration类
@Configuration
@ConditionalOnClass({CacheManager.class})
@ConditionalOnBean({CacheAspectSupport.class})
@ConditionalOnMissingBean(
value = {CacheManager.class},
name = {"cacheResolver"}
)
@EnableConfigurationProperties({CacheProperties.class})
@AutoConfigureBefore({HibernateJpaAutoConfiguration.class})
@AutoConfigureAfter({CouchbaseAutoConfiguration.class, HazelcastAutoConfiguration.class, RedisAutoConfiguration.class})
//我们注意到这里的@Import会给容器中导入许多缓存的组件(如redis等等)
@Import({CacheAutoConfiguration.CacheConfigurationImportSelector.class})
public class CacheAutoConfiguration {
static final String VALIDATOR_BEAN_NAME = "cacheAutoConfigurationValidator";
public CacheAutoConfiguration() {
}
2. 缓存的配置类
通过debug启动主程序可以知道导入的缓存组件有
RedisCacheConfiguration
SimpleCacheConfiguration
GenericCacheConfiguration
JCacheCacheConfiguration
EhCacheCacheConfiguration
。。。。
等11种缓存组件,如果我们没有在pom中添加任何的starter,springboot会默认匹配SimpleCacheConfiguration
3.SimpleCacheConfiguration做了什么呢?
SimpleCacheConfiguration给容器中注册了一个缓存管理器cacheManager,用来管理缓存的获取和创建,并把数据保存在concurrentMap中。 如下代码
@Bean
//注册了一个缓存管理器
public ConcurrentMapCacheManager cacheManager() {
ConcurrentMapCacheManager cacheManager = new ConcurrentMapCacheManager();
List<String> cacheNames = this.cacheProperties.getCacheNames();
//获取缓存的名字,如果为空则新建,新建的name为我们定义的
if (!cacheNames.isEmpty()) {
cacheManager.setCacheNames(cacheNames);
}
return (ConcurrentMapCacheManager)this.customizerInvoker.customize(cacheManager);
}
4.具体实现(不使用redis时)
4.1 首先在主启动类中加入开启缓存注解
@SpringBootApplication
@EnableScheduling //开启定时任务
@EnableCaching //开启缓存
@MapperScan(basePackages = {"com.example.demo.mapper"})
public class DemoApplication {
SpringApplication.run(DemoApplication.class, args)
}
4.2 在需要开启缓存的地方加入 @Cacheable
@Cacheable(cacheNames = {"emp"}) //当前查询运用了缓存
@Override
public User getUserById(Integer id) {
User user = userMapper.selectByPrimaryKey(id);
return user;
}
缓存的几个重要注解
示例:
@Transactional(readOnly = false)
@CacheEvict(value = "user",key="'user_'+#user.userId",allEntries=false,beforeInvocation=true)
public int updateBuyer(User user,Buyer buyer) {
int i = userMapper.updateByPrimaryKeySelective(user);
return i;
}
//注意:如果是删除,尽量加上beforeInvocation=true,保证在方法执行前就清空缓存
5.@Cacheable运行流程
5.1 方法运行之前,先去查询缓存,根据缓存的名字去获取,如果第一次获取没有这个对应名称的缓存,则会自动创建缓存组件。
5.2 在缓存中使用key-value的形式来存储和查找数据
key是按照某种策略生成的,是可以自定义生成方式的
5.3 没有查到缓存就调用目标方法
5.4 将目标方法返回的结果,放进缓存中
6在使用@CachePut时要注意 它即调用方法,有更新缓存
运行时机 :先调用目标方法,再将目标方法放进缓存
在设计key时 :
1.key = “#employee.id” 使用传入的员工id
2.key = “#result.id” 使用返回后的id
两者都可以,
但是@Cacheable 不能用“#result.id”