【深入浅出Spring原理及实战】「缓存Cache开发系列」带你深入分析Spring所提供的缓存Cache功能的开发实战指南(一)https://developer.aliyun.com/article/1471011
配置文件结合Bean装配
@Value("${caffeine.spec}") private String caffeineSpec; @Bean(name = "caffeineSpec") public CacheManager cacheManagerWithCaffeineFromSpec(){ CaffeineSpec spec = CaffeineSpec.parse(caffeineSpec); Caffeine caffeine = Caffeine.from(spec); // 或使用 Caffeine caffeine = Caffeine.from(caffeineSpec); CaffeineCacheManager cacheManager = new CaffeineCacheManager(); cacheManager.setCaffeine(caffeine); cacheManager.setCacheNames(getNames()); return cacheManager; }
实现CacheLoader
CacheLoader是cache的一种加载策略,key不存在或者key过期之类的都可以通过CacheLoader来自定义获得/重新获得数据。使用refreshAfterWrite必须要设置cacheLoader
java
复制代码
@Configuration public class CacheConfig { @Bean public CacheLoader<Object, Object> cacheLoader() { CacheLoader<Object, Object> cacheLoader = new CacheLoader<Object, Object>() { @Override public Object load(Object key) throws Exception { return null; } // 达到配置文件中的refreshAfterWrite所指定的时候回处罚这个事件方法 @Override public Object reload(Object key, Object oldValue) throws Exception { return oldValue; //可以在这里处理重新加载策略,本例子,没有处理重新加载,只是返回旧值。 } }; return cacheLoader; } }
CacheLoader实质是一个监听,处上述load与reload还包含,expireAfterCreate,expireAfterUpdate,expireAfterRead等可以很灵活的配置CacheLoader。
EhCache
EhCache 是一个纯Java的进程内缓存框架,具有快速、精干等特点,是Hibernate中默认CacheProvider。Ehcache是一种广泛使用的开源Java分布式缓存。主要面向通用缓存,Java EE和轻量级容器。它具有内存和磁盘存储,缓存加载器,缓存扩展,缓存异常处理程序,一个gzip缓存servlet过滤器,支持REST和SOAP api等特点。
导入依赖
引入springboot-cache和ehcache。需要注意,EhCache不需要配置version,SpringBoot的根pom已经集成了。
xml
复制代码
<dependency> <groupId>net.sf.ehcache</groupId> <artifactId>ehcache</artifactId> </dependency>
加入配置:
properties
复制代码
spring.cache.type=ehcache # 配置ehcache缓存 spring.cache.ehcache.config=classpath:/ehcache.xml # 指定ehcache配置文件路径 ,可以不用写,因为默认就是这个路径,SpringBoot会自动扫描
ehcache配置文件
EhCache的配置文件ehcache.xml只需要放到类路径下面,SpringBoot会自动扫描。
xml
复制代码
<ehcache> <!-- 磁盘存储:指定一个文件目录,当EHCache把数据写到硬盘上时,将把数据写到这个文件目录下 path:指定在硬盘上存储对象的路径 path可以配置的目录有: user.home(用户的家目录) user.dir(用户当前的工作目录) java.io.tmpdir(默认的临时目录) ehcache.disk.store.dir(ehcache的配置目录) 绝对路径(如:d:\\ehcache) 查看路径方法:String tmpDir = System.getProperty("java.io.tmpdir"); --> <diskStore path="java.io.tmpdir" /> <!-- defaultCache:默认的缓存配置信息,如果不加特殊说明,则所有对象按照此配置项处理 maxElementsInMemory:设置了缓存的上限,最多存储多少个记录对象 eternal:代表对象是否永不过期 (指定true则下面两项配置需为0无限期) timeToIdleSeconds:最大的发呆时间 /秒 timeToLiveSeconds:最大的存活时间 /秒 overflowToDisk:是否允许对象被写入到磁盘 说明:下列配置自缓存建立起600秒(10分钟)有效 。 在有效的600秒(10分钟)内,如果连续120秒(2分钟)未访问缓存,则缓存失效。 就算有访问,也只会存活600秒。 --> <defaultCache maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="600" timeToLiveSeconds="600" overflowToDisk="true" /> <!-- 按缓存名称的不同管理策略 --> <cache name="myCache" maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="600" overflowToDisk="true" /> </ehcache>
装配
SpringBoot会为我们自动配置 EhCacheCacheManager 这个Bean,如果想自定义设置一些个性化参数时,通过Java Config形式配置。
java
复制代码
@Configuration @EnableCaching public class CacheConfig { @Bean public CacheManager cacheManager() { return new EhCacheCacheManager(ehCacheCacheManager().getObject()); } @Bean public EhCacheManagerFactoryBean ehCacheCacheManager() { EhCacheManagerFactoryBean cmfb = new EhCacheManagerFactoryBean(); cmfb.setConfigLocation(new ClassPathResource("ehcache.xml")); cmfb.setShared(true); return cmfb; } }
Redis Cache
Redis 优势
- 性能极高 – Redis能读的速度是110000次/s,写的速度是81000次/s 。
- 丰富的数据类型 – Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。
- 原子 – Redis的所有操作都是原子性的,意思就是要么成功执行要么失败完全不执行。单个操作是原子性的。多个操作也支持事务,即原子性,通过MULTI和EXEC指令包起来。
- 丰富的特性 – Redis还支持 publish/subscribe, 通知, key 过期等等特性
- 分布式横向扩展
导入依赖
不需要spring-boot-starter-cache
xml
复制代码
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
当你导入这一个依赖时,SpringBoot的CacheManager就会使用RedisCache。
Redis使用模式使用pool2连接池,在需要时引用下面的依赖
xml
复制代码
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-pool2 --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> <version>2.6.2</version> </dependency>
配置Redis
properties
复制代码
spring.redis.database=1 # Redis数据库索引(默认为0) spring.redis.host=127.0.0.1 # Redis服务器地址 spring.redis.port=6379 # Redis服务器连接端口 spring.redis.password= # Redis服务器连接密码(默认为空) spring.redis.pool.max-active=1000 # 连接池最大连接数(使用负值表示没有限制) spring.redis.pool.max-wait=-1 # 连接池最大阻塞等待时间(使用负值表示没有限制) spring.redis.pool.max-idle=10 # 连接池中的最大空闲连接 spring.redis.pool.min-idle=2 # 连接池中的最小空闲连接 spring.redis.timeout=0 # 连接超时时间(毫秒)
如果你的Redis这时候已经可以启动程序了。
装配
如果需要自定义缓存配置可以通过,继承CachingConfigurerSupport类,手动装配,如果一切使用默认配置可不必
装配序列化类型
xml
复制代码
@Bean public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory connectionFactory) { // 配置redisTemplate RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(connectionFactory); redisTemplate.setKeySerializer(new StringRedisSerializer());//key序列化 redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());//value序列化 redisTemplate.afterPropertiesSet(); return redisTemplate; }
装配过期时间
java
复制代码
/** * 通过RedisCacheManager配置过期时间 * * @param redisConnectionFactory * @return */ @Bean public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) { RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig() .entryTtl(Duration.ofHours()); // 设置缓存有效期一小时 return RedisCacheManager .builder(RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory)) .cacheDefaults(redisCacheConfiguration).build(); }
自定义缓存配置文件,继承 CachingConfigurerSupport
java
复制代码
/** * * Created by huanl on 2017/8/22. */ @Configuration @EnableCaching public class RedisConfig extends CachingConfigurerSupport{ public RedisConfig() { super(); } /** * 指定使用哪一种缓存 * @param redisTemplate * @return */ @Bean public CacheManager cacheManager(RedisTemplate<?,?> redisTemplate) { RedisCacheManager rcm = new RedisCacheManager(redisTemplate); return rcm; } /** * 指定默认的key生成方式 * @return */ @Override public KeyGenerator keyGenerator() { KeyGenerator keyGenerator = new KeyGenerator() { @Override public Object generate(Object o, Method method, Object... objects) { StringBuilder sb = new StringBuilder(); sb.append(o.getClass().getName()); sb.append(method.getName()); for (Object obj : objects) { sb.append(obj.toString()); } return sb.toString(); } }; return keyGenerator; } @Override public CacheResolver cacheResolver() { return super.cacheResolver(); } @Override public CacheErrorHandler errorHandler() { return super.errorHandler(); } /** * redis 序列化策略 ,通常情况下key值采用String序列化策略 * StringRedisTemplate默认采用的是String的序列化策略,保存的key和value都是采用此策略序列化保存的。StringRedisSerializer * RedisTemplate默认采用的是JDK的序列化策略,保存的key和value都是采用此策略序列化保存的。JdkSerializationRedisSerializer * @param factory * @return */ @Bean public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory factory){ RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(factory); // // 使用Jackson2JsonRedisSerialize 替换默认序列化 // Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); // ObjectMapper om = new ObjectMapper(); // om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); // om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); // jackson2JsonRedisSerializer.setObjectMapper(om); // // // //设置value的序列化方式 // redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); // //设置key的序列化方式 // redisTemplate.setKeySerializer(new StringRedisSerializer()); // redisTemplate.setHashKeySerializer(new StringRedisSerializer()); // redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer); //使用fastJson作为默认的序列化方式 GenericFastJsonRedisSerializer genericFastJsonRedisSerializer = new GenericFastJsonRedisSerializer(); redisTemplate.setDefaultSerializer(genericFastJsonRedisSerializer); redisTemplate.setValueSerializer(genericFastJsonRedisSerializer); redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.setHashValueSerializer(genericFastJsonRedisSerializer); redisTemplate.setHashKeySerializer(new StringRedisSerializer()); redisTemplate.afterPropertiesSet(); return redisTemplate; } /** * 转换返回的object为json * @return */ @Bean public HttpMessageConverters fastJsonHttpMessageConverters(){ // 1、需要先定义一个converter 转换器 FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter(); // 2、添加fastJson 的配置信息,比如:是否要格式化返回的json数据 FastJsonConfig fastJsonConfig = new FastJsonConfig(); fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat); // 3、在convert 中添加配置信息 fastConverter.setFastJsonConfig(fastJsonConfig); // 4、将convert 添加到converters当中 HttpMessageConverter<?> converter = fastConverter; return new HttpMessageConverters(converter); } }