@javazjm
2017-11-01T12:45:23.000000Z
字数 11885
阅读 2883
Springboot Cache ehcache redis
Springboot 使用缓存很简单,只需遵循以下几步就可以。
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency>
在启动类上加注解@enableCaching,启用缓存
在需要缓存的方法上,使用注解
1.@Cacheable(cacheNames = "car", key = "#name")将方法的返回值 保存 在缓存“car”中,键由key指定,值是方法的返回值2.@CachePut(cacheNames = "car", key = "#car.name")使用方法的返回值 更新 缓存“car”中,键为key的值3.@CacheEvict(cacheNames = "car", allEntries = true)根据key和condition删除缓存,如果指定allEntries为true,则删除缓存中所有的对象
说明:
这里并没有明确指定缓存提供者,但是Springboot会按照以下顺序寻找提供者:
31.1.1. Generic
31.1.2. JCache (JSR-107)
31.1.3. EhCache 2.x
31.1.4. Hazelcast
31.1.5. Infinispan
31.1.6. Couchbase
31.1.7. Redis
31.1.8. Caffeine
31.1.9. Simple若没有查找到前9类缓存的cacheManager,则会使用最后一个simple缓存,也就是在内存中使用ConcurrentHashMap实现缓存。spring官方建议生产环境中勿使用simple缓存。
本实例就是使用的simple缓存。
注意:
1.
使用RedisTemplate,结果发现redis里查找不到对应的key-value键值对,原因是spring-data-redis的RedisTemplate
V>模板类在操作redis时默认使用JdkSerializationRedisSerializer来进行序列化.
2.
SpringBoot提供了对Redis的自动配置功能,在RedisAutoConfiguration中默认为我们配置了JedisConnectionFactory(客户端连接)、RedisTemplate以及StringRedisTemplate(数据操作模板),其中StringRedisTemplate模板只针对键值对都是字符型的数据进行操作
Spring会找到redisCacheManager,使用redis作为缓存。
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency>
# REDIS (RedisProperties)# Redis数据库索引(默认为0)spring.redis.database=0# Redis服务器地址spring.redis.host=127.0.0.1# Redis服务器连接端口spring.redis.port=6379# Redis服务器连接密码(默认为空)spring.redis.password=# 连接池最大连接数(使用负值表示没有限制)spring.redis.pool.max-active=8# 连接池最大阻塞等待时间(使用负值表示没有限制)spring.redis.pool.max-wait=-1# 连接池中的最大空闲连接spring.redis.pool.max-idle=8# 连接池中的最小空闲连接spring.redis.pool.min-idle=0# 连接超时时间(毫秒)spring.redis.timeout=0
@Entity@Table(name = "userInfo")public class User implements Serializable {@Id@GeneratedValueprivate Long id;@Column(nullable = false)private String userName;@Column(nullable = false)private String passWord;@Column(nullable = false)private String email;@Column(nullable = false, unique = true)private String nickName;@Column(nullable = false)private Date regTime;// setter getter...}
/*** @Cacheable 应用到读取数据的方法上,先从缓存中读取,如果没有再从DB获取数据,然后把数据添加到缓存中* @param id* keyGenerator 和 key 不能同时存在* 否则:Both 'key' and 'keyGenerator' attributes have been set* @return*/@Cacheable(value = "user", key = "'user'+ '_'+ #id", unless = "#result eq null")public User getUserById(Long id) {return entityManager.find(User.class, id);}@Cacheable(value = "user", key = "#root.methodName + '_users'", unless = "#result eq null ")public List<User> getUsers(){return userRepository.findAll();}/*** 使用自定义注解* @param user* @return*/@UserSaveCachepublic User addUser3(User user) {return userRepository.save(user);}
自定义注解
@Caching(put = {@CachePut(value = "user", key = "'user' + #result.id"),@CachePut(value = "user", key = "'user' + #result.nickName"),@CachePut(value = "user", key = "'user' + #result.email"),})@Target({ElementType.METHOD, ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Inheritedpublic @interface UserSaveCache {}
@Configuration@EnableCachingpublic class RedisConfig extends CachingConfigurerSupport {/*** key 生成策略* @return*/@Beanpublic KeyGenerator keyGenerator(){return new KeyGenerator() {@Overridepublic 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();}};}/*** 如果不做额外配置可以不需要,springboot会根据所使用的缓存,自动配置缓存管理器* @param redisTemplate* @return*/@SuppressWarnings("rawtypes")@Beanpublic CacheManager cacheManager(RedisTemplate redisTemplate) {RedisCacheManager rcm = new RedisCacheManager(redisTemplate);//设置缓存过期时间long expireTime = 600;rcm.setDefaultExpiration(expireTime);//秒 管用// System.out.println("通用过期时间:" + expireTime);return rcm;}/*** 连接工厂 默认自动配置JedisConnectionFactory(客户端连接)* @return*/@BeanJedisConnectionFactory jedisConnectionFactory() {return new JedisConnectionFactory();}@Beanpublic RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory){RedisTemplate<String, String> template = new RedisTemplate<>();RedisSerializer<String> stringRedisSerializer = new StringRedisSerializer();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);template.setConnectionFactory(factory);// 开启事务支持template.setEnableTransactionSupport(true);// template.setEnableDefaultSerializer(false); // 将任何序列化器设置为null,并使用原始字节数组来使用RedisTemplate//key序列化方式 stringRedisSerializertemplate.setKeySerializer(stringRedisSerializer);template.setHashKeySerializer(stringRedisSerializer);//value序列化 jackson2JsonRedisSerializertemplate.setValueSerializer(jackson2JsonRedisSerializer);// template.setValueSerializer(new RedisObjectSerializer()); // value是byte字节 \xAC\xED\x00\x05t\x00\x09\xE5\xBC\xA0\xE4\xBA\x8C\xE7\xA3\x8Atemplate.setHashValueSerializer(jackson2JsonRedisSerializer);template.afterPropertiesSet();return template;}}
@Autowiredprivate StringRedisTemplate stringRedisTemplate; // 只能操作字符串@Autowiredprivate RedisTemplate redisTemplate; // 通用性广@Autowiredprivate UserService userService;@Testpublic void testSer(){User user = new User("张无忌", "123456", "itzjm@qq.com", "zhangwuji", new Date());User user1 = userService.addUser3(user);System.out.println(user1.getId()+"=======");// 16User userById = userService.getUserById(1L);System.out.println(userById);}
可以将redis的操作封装到一个类中RedisCacheService,直接在所需要的类中引入即可。
代码详见:https://github.com/JavaerZJM/springboot-workspace
参考:
根据官网:http://www.ehcache.org/blog/2016/05/18/ehcache3_jsr107_spring.html
<!-- ehcache 3.x --><dependency><groupId>org.ehcache</groupId><artifactId>ehcache</artifactId><version>3.3.1</version></dependency><!-- JSR107 API --><dependency><groupId>javax.cache</groupId><artifactId>cache-api</artifactId></dependency><!-- springboot cache --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId></dependency>
需要在application.properties文件中配置:包括类路径和ehcache。xml文件
# ehcache配置spring.cache.jcache.config=classpath:ehcache.xml
@Cacheable(value = "studentCache", key = "'student_'+#id")@Overridepublic Student findById(Long id) {return studentDao.findOne(id);}
<configxmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'xmlns='http://www.ehcache.org/v3'xmlns:jsr107='http://www.ehcache.org/v3/jsr107'><service><jsr107:defaults><!-- 定义别名为 "studentCache"的缓存,继承自缓存模板“heap - cache” --><jsr107:cache name="studentCache" template="heap-cache"/></jsr107:defaults></service><cache-template name="heap-cache"><!-- 添加缓存事件监听器,当以下事件发生时,被EventLogger记录 --><listeners><listener><class>com.jimzhang.listener.EventLoggerListener</class><event-firing-mode>ASYNCHRONOUS</event-firing-mode><event-ordering-mode>UNORDERED</event-ordering-mode><events-to-fire-on>CREATED</events-to-fire-on><events-to-fire-on>UPDATED</events-to-fire-on><events-to-fire-on>EXPIRED</events-to-fire-on><events-to-fire-on>REMOVED</events-to-fire-on><events-to-fire-on>EVICTED</events-to-fire-on></listener></listeners><resources><!-- 堆设置保存2000个条目 --><heap unit="entries">2000</heap><!-- 存储空间100M --><offheap unit="MB">100</offheap></resources></cache-template></config>
@Component// 开启缓存@EnableCachingpublic class JSRCacheConfiguration implements JCacheManagerCustomizer {@Overridepublic void customize(CacheManager cacheManager) {cacheManager.createCache("studentCache", new MutableConfiguration<>().setExpiryPolicyFactory(TouchedExpiryPolicy.factoryOf(new Duration(TimeUnit.SECONDS, 10))).setStoreByValue(false).setStatisticsEnabled(true));}}
EventLoggerListener
public class EventLoggerListener implements CacheEventListener<Object, Object> {private static final Logger LOGGER = LoggerFactory.getLogger(EventLoggerListener.class);@Overridepublic void onEvent(CacheEvent<?, ?> event) {LOGGER.info("Event: " + event.getType() + " Key: " + event.getKey() + " old value: " + event.getOldValue()+ " new value: " + event.getNewValue());}}
单元测试:
@Testpublic void test() {Student student = studentService.findById(1L);logger.info("学生信息----:" + student.toString());Student student2 = studentService.findById(1L);logger.info("学生信息2----:" + student2.toString());}
<!-- Spring 对Cache 的支持 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId></dependency><!--EHCache 相关依赖 2.x--><dependency><groupId>net.sf.ehcache</groupId><artifactId>ehcache</artifactId></dependency>
创建ehcache.xml文件
<?xml version="1.0" encoding="UTF-8"?><ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"updateCheck="false"><defaultCacheeternal="false"maxElementsInMemory="1000"overflowToDisk="false"diskPersistent="false"timeToIdleSeconds="0"timeToLiveSeconds="600"memoryStoreEvictionPolicy="LRU" /><cachename="studentCache"eternal="false"maxElementsInMemory="100"overflowToDisk="false"diskPersistent="false"timeToIdleSeconds="0"timeToLiveSeconds="300"memoryStoreEvictionPolicy="LRU" />
配置文件类
@SpringBootConfiguration/** 启用缓存 **/@EnableCachingpublic class EHCacheConfiguration {private final Logger logger = LoggerFactory.getLogger(this.getClass());/*** ehcache 主要的管理器** @param bean* @return*/@Beanpublic EhCacheCacheManager ehCacheCacheManager(EhCacheManagerFactoryBean bean) {logger.info("CacheConfiguration.ehCacheCacheManager()");// return new EhCacheCacheManager(bean.getObject());return new EhCacheCacheManager(ehCacheManagerFactoryBean().getObject());}/*** 默认情况下,其实可以不配置,EhCacheCacheConfiguration 类中默认使用EHCache 就是使用的classpath:ehcache.xml** @return*/@Beanpublic EhCacheManagerFactoryBean ehCacheManagerFactoryBean() {logger.info("CacheConfiguration.ehCacheManagerFactoryBean()");EhCacheManagerFactoryBean cacheManagerFactoryBean = new EhCacheManagerFactoryBean();cacheManagerFactoryBean.setConfigLocation(new ClassPathResource("config/ehcache.xml"));//也说是说通过这个来设置cache的基地是这里的Spring独用,还是跟别的(如hibernate的Ehcache共享)cacheManagerFactoryBean.setShared(true);return cacheManagerFactoryBean;}}
在application.properties配置文件制定ehcache.xml的位置
spring.cache.ehcache.config=classpath:config/another-config.xml
其实,可以不指定,Springboot只要发现了该配置文件,就会创建EhCache的缓存管理器。
代替ehcache.xml配置文件
@SpringBootConfiguration@EnableCachingpublic class CacheConfig {@BeanCacheManager cacheManager() {return new EhCacheCacheManager(ehCacheManager());}@Bean(destroyMethod = "shutdown")net.sf.ehcache.CacheManager ehCacheManager() {CacheConfiguration cacheConfiguration = new CacheConfiguration();cacheConfiguration.setName("studentCache");cacheConfiguration.setTimeToLiveSeconds(600); // 保存10分钟cacheConfiguration.setMemoryStoreEvictionPolicy("LRU");cacheConfiguration.setMaxEntriesLocalHeap(1000);net.sf.ehcache.config.Configuration config = new net.sf.ehcache.config.Configuration();config.addCache(cacheConfiguration);return new net.sf.ehcache.CacheManager(config);}}
@Cacheable(value = "studentCache", key = "'student_'+#id")@Overridepublic Student findById(Long id) {return studentDao.findOne(id);}
@Testpublic void test() {Student student = studentService.findById(1L);logger.info("学生信息----:" + student.toString());Student student2 = studentService.findById(1L);logger.info("学生信息2----:" + student2.toString());}
参考: