[源]:https://blog.youkuaiyun.com/caiwufei/article/details/78863804
springboot同时整合redis和ehcache,redis和ehcache各种工作,互补干扰。
1.maven依赖
- <!– 本地缓存依赖 –>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-cache</artifactId>
- </dependency>
- <dependency>
- <groupId>org.ehcache</groupId>
- <artifactId>ehcache</artifactId>
- </dependency>
- <dependency>
- <groupId>javax.cache</groupId>
- <artifactId>cache-api</artifactId>
- </dependency>
- <!– redis –>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-data-redis</artifactId>
- </dependency>
<!-- 本地缓存依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>
<dependency>
<groupId>javax.cache</groupId>
<artifactId>cache-api</artifactId>
</dependency>
<!-- redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
同时把ehcache的版本设置下,我设置的3.4.0。在maven的属性中添加<ehcache3.version>3.4.0</ehcache3.version>,即可以覆盖父依赖的。
2.在application.properties中添加相关配置。主要是ehcache和redis的
- #——————-ehcache———————-
- spring.cache.type=jcache
- spring.cache.jcache.config=classpath:/config/ehcache.xml
- spring.cache.jcache.provider=org.ehcache.jsr107.EhcacheCachingProvider
- #——————-redis————————
- spring.redis.host=ip
- spring.redis.port=port
- spring.redis.password=pwd
- spring.redis.pool.max-active=10
- spring.redis.pool.max-wait=-1
- spring.redis.pool.max-idle=5
- spring.redis.pool.min-idle=0
- spring.redis.timeout=50
- spring.redis.ssl=false
#-------------------ehcache----------------------
spring.cache.type=jcache
spring.cache.jcache.config=classpath:/config/ehcache.xml
spring.cache.jcache.provider=org.ehcache.jsr107.EhcacheCachingProvider
——————-redis————————
spring.redis.host=ip
spring.redis.port=port
spring.redis.password=pwd
spring.redis.pool.max-active=10
spring.redis.pool.max-wait=-1
spring.redis.pool.max-idle=5
spring.redis.pool.min-idle=0
spring.redis.timeout=50
spring.redis.ssl=false
3.在添加stater和配置属性后,系统启动的时候两种缓存都会加载。jecache默认为ehcache。
但是我想要的是,我使用缓存注解的时候,指定缓存一处,要么是本地,要么是redis。spring提供了自己的一套缓存管理器来管理其他第三方的缓存。集成接口实现自己的即可。
添加redis的starter的时候,redistemplate已经被注入了,但是是<k,v>泛型的。
- package com.caiwufei.springboot;
- import java.net.URISyntaxException;
- import javax.cache.Caching;
- import javax.cache.spi.CachingProvider;
- import org.springframework.beans.factory.annotation.Qualifier;
- import org.springframework.cache.CacheManager;
- import org.springframework.cache.annotation.EnableCaching;
- import org.springframework.cache.jcache.JCacheCacheManager;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Primary;
- import org.springframework.data.redis.cache.RedisCacheManager;
- import org.springframework.data.redis.core.RedisTemplate;
- import org.springframework.data.redis.serializer.StringRedisSerializer;
- import com.caiwufei.common.cache.AppCacheManager;
- import com.caiwufei.entity.base.BaseEntity;
- @EnableCaching
- @SuppressWarnings({ “rawtypes”, “unchecked” })
- public class CacheConfig{
- /* @Autowired
- private RedisConnectionFactory factory;*/
- @Bean(“redisCacheManager”)
- public RedisCacheManager redisCacheManager(@Qualifier(“redisTemplate”)RedisTemplate redisTemplate) {
- //设置数据存入 redis 的序列化方式
- redisTemplate.setKeySerializer(new StringRedisSerializer());
- redisTemplate.setHashKeySerializer(new StringRedisSerializer());
- redisTemplate.setHashValueSerializer(new BaseEntity<>());
- redisTemplate.setValueSerializer(new BaseEntity<>());
- return new RedisCacheManager(redisTemplate);
- }
- @Bean(“jCacheCacheManager”)
- public JCacheCacheManager jCacheCacheManager() throws URISyntaxException {
- CachingProvider provider = Caching.getCachingProvider();
- JCacheCacheManager jCacheCacheManager = new JCacheCacheManager();
- javax.cache.CacheManager eh107CacheManager = provider.getCacheManager(getClass().getResource(”/config/ehcache.xml”).toURI(), getClass().getClassLoader());
- jCacheCacheManager.setCacheManager(eh107CacheManager);
- return jCacheCacheManager;
- }
- @Bean(“cacheManager”)
- @Primary
- public CacheManager initMixCacheManager(RedisCacheManager redisCacheManager, JCacheCacheManager ehCacheManager) {
- AppCacheManager cacheManager = new AppCacheManager();
- cacheManager.setRedisCacheManager(redisCacheManager);
- cacheManager.setEhCacheCacheManager(ehCacheManager);
- return cacheManager;
- }
- /**
- * 实例化 HashOperations 对象,可以使用 Hash 类型操作
- */
- /**
- * 实例化 ValueOperations 对象,可以使用 String 操作
- */
- /**
- * 实例化 ListOperations 对象,可以使用 List 操作
- */
- /**
- * 实例化 SetOperations 对象,可以使用 Set 操作
- */
- /**
- * 实例化 ZSetOperations 对象,可以使用 ZSet 操作
- */
- }
package com.caiwufei.springboot;
import java.net.URISyntaxException;
import javax.cache.Caching;
import javax.cache.spi.CachingProvider;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.jcache.JCacheCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import com.caiwufei.common.cache.AppCacheManager;
import com.caiwufei.entity.base.BaseEntity;
@EnableCaching
@SuppressWarnings({ "rawtypes", "unchecked" })
public class CacheConfig{
/* @Autowired
private RedisConnectionFactory factory;*/
@Bean("redisCacheManager")
public RedisCacheManager redisCacheManager(@Qualifier("redisTemplate")RedisTemplate redisTemplate) {
//设置数据存入 redis 的序列化方式
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(new BaseEntity<>());
redisTemplate.setValueSerializer(new BaseEntity<>());
return new RedisCacheManager(redisTemplate);
}
@Bean("jCacheCacheManager")
public JCacheCacheManager jCacheCacheManager() throws URISyntaxException {
CachingProvider provider = Caching.getCachingProvider();
JCacheCacheManager jCacheCacheManager = new JCacheCacheManager();
javax.cache.CacheManager eh107CacheManager = provider.getCacheManager(getClass().getResource("/config/ehcache.xml").toURI(), getClass().getClassLoader());
jCacheCacheManager.setCacheManager(eh107CacheManager);
return jCacheCacheManager;
}
@Bean("cacheManager")
@Primary
public CacheManager initMixCacheManager(RedisCacheManager redisCacheManager, JCacheCacheManager ehCacheManager) {
AppCacheManager cacheManager = new AppCacheManager();
cacheManager.setRedisCacheManager(redisCacheManager);
cacheManager.setEhCacheCacheManager(ehCacheManager);
return cacheManager;
}
/**
* 实例化 HashOperations 对象,可以使用 Hash 类型操作
*/
/**
* 实例化 ValueOperations 对象,可以使用 String 操作
*/
/**
* 实例化 ListOperations 对象,可以使用 List 操作
*/
/**
* 实例化 SetOperations 对象,可以使用 Set 操作
*/
/**
* 实例化 ZSetOperations 对象,可以使用 ZSet 操作
*/
}
下面是appcachemanger的实现
- package com.caiwufei.common.cache;
- import java.util.ArrayList;
- import java.util.Collection;
- import org.springframework.cache.Cache;
- import org.springframework.cache.CacheManager;
- public class AppCacheManager implements CacheManager{
- private CacheManager redisCacheManager;
- private CacheManager ehCacheManager;
- private final static String redisPrefix = “redis”;
- @Override
- public Cache getCache(String name) {
- if (name.startsWith(redisPrefix)) {
- return redisCacheManager.getCache(name);
- } else {
- return ehCacheManager.getCache(name);
- }
- }
- @Override
- public Collection<String> getCacheNames() {
- Collection<String> cacheNames = new ArrayList<String>();
- if (redisCacheManager != null) {
- cacheNames.addAll(redisCacheManager.getCacheNames());
- }
- if (ehCacheManager != null) {
- cacheNames.addAll(ehCacheManager.getCacheNames());
- }
- return cacheNames;
- }
- public CacheManager getRedisCacheManager() {
- return redisCacheManager;
- }
- public void setRedisCacheManager(CacheManager redisCacheManager) {
- this.redisCacheManager = redisCacheManager;
- }
- public CacheManager getEhCacheCacheManager() {
- return ehCacheManager;
- }
- public void setEhCacheCacheManager(CacheManager ehcacheCacheManager) {
- this.ehCacheManager = ehcacheCacheManager;
- }
- }
package com.caiwufei.common.cache;
import java.util.ArrayList;
import java.util.Collection;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
public class AppCacheManager implements CacheManager{
private CacheManager redisCacheManager;
private CacheManager ehCacheManager;
private final static String redisPrefix = "redis";
@Override
public Cache getCache(String name) {
if (name.startsWith(redisPrefix)) {
return redisCacheManager.getCache(name);
} else {
return ehCacheManager.getCache(name);
}
}
@Override
public Collection<String> getCacheNames() {
Collection<String> cacheNames = new ArrayList<String>();
if (redisCacheManager != null) {
cacheNames.addAll(redisCacheManager.getCacheNames());
}
if (ehCacheManager != null) {
cacheNames.addAll(ehCacheManager.getCacheNames());
}
return cacheNames;
}
public CacheManager getRedisCacheManager() {
return redisCacheManager;
}
public void setRedisCacheManager(CacheManager redisCacheManager) {
this.redisCacheManager = redisCacheManager;
}
public CacheManager getEhCacheCacheManager() {
return ehCacheManager;
}
public void setEhCacheCacheManager(CacheManager ehcacheCacheManager) {
this.ehCacheManager = ehcacheCacheManager;
}
}
4此时容器中有三个缓存管理器,一个是jcache,一个是redis的,还有一个是我们自己实现的,但是我们设置我们自己为primary即可。
5测试
dao层的
- public interface SSAccountInfoDao extends BaseMapper<SSAccountInfo>{
- @Cacheable(cacheNames=“redis-SSAccountInfo”, key=“‘SSAccountInfo_’ + #root.args[0].accountId”, unless=“#result==null”)
- public SSAccountInfo queryByAccountIdForTestRedis(SSAccountInfo account);
- @Cacheable(cacheNames=“SSAccountInfo”, key=“‘SSAccountInfo_’ + #root.args[0].accountId”, unless=“#result==null”) //ehcache.xml需要配置
- public SSAccountInfo queryByAccountIdForTestEhcache(SSAccountInfo a);
- }
public interface SSAccountInfoDao extends BaseMapper<SSAccountInfo>{
@Cacheable(cacheNames="redis-SSAccountInfo", key="'SSAccountInfo_' + #root.args[0].accountId", unless="#result==null")
public SSAccountInfo queryByAccountIdForTestRedis(SSAccountInfo account);
@Cacheable(cacheNames="SSAccountInfo", key="'SSAccountInfo_' + #root.args[0].accountId", unless="#result==null") //ehcache.xml需要配置
public SSAccountInfo queryByAccountIdForTestEhcache(SSAccountInfo a);
}
controller层的- @GetMapping(“/testcache”)
- public Object testcache() {
- SSAccountInfo param = new SSAccountInfo();
- param.setAccountId(”F54045545”);
- long t = System.currentTimeMillis();
- ssAccountInfoService.queryByAccountIdForTestEhcache(param);
- System.out.println(”TestEhcache第一次查询耗时:” + (System.currentTimeMillis()-t));
- t = System.currentTimeMillis();
- ssAccountInfoService.queryByAccountIdForTestEhcache(param);
- System.out.println(”TestEhcache第二次查询耗时:” + (System.currentTimeMillis()-t));
- JCacheCache jCache = (JCacheCache) cacheManager.getCache(”SSAccountInfo”);
- if(jCache.getNativeCache().containsKey((“SSAccountInfo_” + param.getAccountId()))){
- System.out.println(”————–ehcache存在————-“);
- SSAccountInfo ehcache = (SSAccountInfo) jCache.getNativeCache().get(”SSAccountInfo_” + param.getAccountId());
- System.out.println(”ehcache__” + ehcache.getAccountId() + “” + ehcache.getAccountName());
- }else {
- System.out.println(”————–ehcache不存在————-“);
- }
- t = System.currentTimeMillis();
- ssAccountInfoService.queryByAccountIdForTestRedis(param);
- System.out.println(”TestRedis第一次查询耗时:” + (System.currentTimeMillis()-t));
- t = System.currentTimeMillis();
- ssAccountInfoService.queryByAccountIdForTestRedis(param);
- System.out.println(”TestRedis第二次查询耗时:” + (System.currentTimeMillis()-t));
- if(RedisTemplate.hasKey(“SSAccountInfo” + param.getAccountId())) {
- System.out.println(”————–redis存在————-“);
- SSAccountInfo redis = (SSAccountInfo) RedisTemplate.get(”SSAccountInfo_” + param.getAccountId());
- System.out.println(”redis” + redis.getAccountId() + ”_” + redis.getAccountName());
- }else {
- System.out.println(”————–redis不存在————-“);
- }
- return “YES”;
- }
@GetMapping("/testcache")
public Object testcache() {
SSAccountInfo param = new SSAccountInfo();
param.setAccountId("F54045545");
long t = System.currentTimeMillis();
ssAccountInfoService.queryByAccountIdForTestEhcache(param);
System.out.println("TestEhcache第一次查询耗时:" + (System.currentTimeMillis()-t));
t = System.currentTimeMillis();
ssAccountInfoService.queryByAccountIdForTestEhcache(param);
System.out.println("TestEhcache第二次查询耗时:" + (System.currentTimeMillis()-t));
JCacheCache jCache = (JCacheCache) cacheManager.getCache("SSAccountInfo");
if(jCache.getNativeCache().containsKey(("SSAccountInfo_" + param.getAccountId()))){
System.out.println("--------------ehcache存在-------------");
SSAccountInfo ehcache = (SSAccountInfo) jCache.getNativeCache().get("SSAccountInfo_" + param.getAccountId());
System.out.println("ehcache__" + ehcache.getAccountId() + "___" + ehcache.getAccountName());
}else {
System.out.println("--------------ehcache不存在-------------");
}
t = System.currentTimeMillis();
ssAccountInfoService.queryByAccountIdForTestRedis(param);
System.out.println("TestRedis第一次查询耗时:" + (System.currentTimeMillis()-t));
t = System.currentTimeMillis();
ssAccountInfoService.queryByAccountIdForTestRedis(param);
System.out.println("TestRedis第二次查询耗时:" + (System.currentTimeMillis()-t));
if(RedisTemplate.hasKey("SSAccountInfo_" + param.getAccountId())) {
System.out.println("--------------redis存在-------------");
SSAccountInfo redis = (SSAccountInfo) RedisTemplate.get("SSAccountInfo_" + param.getAccountId());
System.out.println("redis__" + redis.getAccountId() + "___" + redis.getAccountName());
}else {
System.out.println("--------------redis不存在-------------");
}
return "YES";
}</pre>service层的省略,下面是结果
- TestEhcache第一次查询耗时:3760
- TestEhcache第二次查询耗时:7
- ————–ehcache存在————-
- ehcache__F54045545___null
- TestRedis第一次查询耗时:126
- TestRedis第二次查询耗时:12
- ————–redis存在————-
- redis__F54045545___null
TestEhcache第一次查询耗时:3760
TestEhcache第二次查询耗时:7
--------------ehcache存在-------------
ehcache__F54045545___null
TestRedis第一次查询耗时:126
TestRedis第二次查询耗时:12
--------------redis存在-------------
redis__F54045545___null
很明显,it works!
这种方法也可以使用来隔离使用注解的时候不缓存到redis,redis缓存可以使用模板操作。当然也可以直接使用注解,看个人喜欢。