配置类如下注意红色标记的部分:
package com.zyc.zspringboot.config;
import com.zyc.zspringboot.cache.MyCacheManager;
import com.zyc.zspringboot.cache.MyCacheTemplate;
import com.zyc.zspringboot.cache.MyRedisCache;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.ehcache.EhCacheCacheManager;
import org.springframework.cache.ehcache.EhCacheManagerFactoryBean;
import org.springframework.context.annotation.AdviceMode;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import redis.clients.jedis.JedisPoolConfig;
import java.util.ArrayList;
import java.util.List;
/**
* ClassName: RedisConfig
*
* @author zyc-admin
* @date 2018年1月23日
* @Description:
*/
@Configuration
@EnableCaching(mode = AdviceMode.PROXY)
// model属性默认proxy
// mode属性,可以选择值proxy和aspectj。默认使用proxy。当mode为proxy时,
// 只有缓存方法在外部被调用的时候才会生效。这也就意味着如果一个缓存方法在一个对
// 象的内部被调用SpringCache是不会发生作用的。而mode为aspectj时,就不会有
// 这种问题了。另外使用proxy的时候,只有public方法上的@Cacheable才会发生作用。
// 如果想非public上的方法也可以使用那么就把mode改成aspectj。
@ConfigurationProperties(prefix = "spring.redis")
// 使用@ConfigurationProperties 需要实现属性的getter setter方法,
// 1.5之前版本需要在启动类上使用@EnableConfigurationProperties进行激活,1.5之后直接在配置类上使用@Component,
// 由于本类使用@Configuration注解包含了@Component就不用在声明@Component,
// 这样就可以直接在其他类中使用@Autowired直接把此类注入进来
// extends CachingConfigurerSupport
public class RedisConfig {
private String hostName;
private int port;
private int timeOut;
private int maxIdle;// 最大空闲连接数, 默认8个
private int maxWaitMillis;// 获取连接时的最大等待毫秒数
private boolean testOnBorrow;// 在获取连接的时候检查有效性, 默认false
private boolean testWhileIdle;// 空闲是否检查是否有效,默认为false
public String getHostName() {
return hostName;
}
public void setHostName(String hostName) {
this.hostName = hostName;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public int getTimeOut() {
return timeOut;
}
public void setTimeOut(int timeOut) {
this.timeOut = timeOut;
}
public int getMaxIdle() {
return maxIdle;
}
public void setMaxIdle(int maxIdle) {
this.maxIdle = maxIdle;
}
public int getMaxWaitMillis() {
return maxWaitMillis;
}
public void setMaxWaitMillis(int maxWaitMillis) {
this.maxWaitMillis = maxWaitMillis;
}
public boolean isTestOnBorrow() {
return testOnBorrow;
}
public void setTestOnBorrow(boolean testOnBorrow) {
this.testOnBorrow = testOnBorrow;
}
public boolean isTestWhileIdle() {
return testWhileIdle;
}
public void setTestWhileIdle(boolean testWhileIdle) {
this.testWhileIdle = testWhileIdle;
}
@Bean("jedisPoolConfig")
public JedisPoolConfig jedisPoolConfig() {
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxIdle(maxIdle);
jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);
jedisPoolConfig.setTestOnBorrow(true);
jedisPoolConfig.setTestWhileIdle(false);
return jedisPoolConfig;
}
@Bean
public JedisConnectionFactory redisConnectionFactory(
JedisPoolConfig jedisPoolConfig) {
// 如果集群使用new JedisConnectionFactory(new
// RedisClusterConfiguration()),集群配置在RedisClusterConfiguration,这里省略具体配置
JedisConnectionFactory redisConnectionFactory = new JedisConnectionFactory();
redisConnectionFactory.setPoolConfig(jedisPoolConfig);
redisConnectionFactory.setHostName(hostName);
redisConnectionFactory.setPort(port);
redisConnectionFactory.setTimeout(timeOut);
return redisConnectionFactory;
}
/**
* RedisTemplate配置
*
* @param redisConnectionFactory
* @return RedisTemplate
*/
@Bean
public RedisTemplate redisTemplate(
JedisConnectionFactory redisConnectionFactory) {
RedisTemplate redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
RedisSerializer redisSerializer = new StringRedisSerializer();
redisTemplate.setKeySerializer(redisSerializer);
// Jackson2JsonRedisSerializer
自定义CacheManager如下:
package com.zyc.zspringboot.cache;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import java.util.Collection;
/**
* @author zyc-admin
* @data 2018-03-20 10:12
**/
public class MyCacheManager implements CacheManager {
private MyCacheTemplate myCacheTemplate;
private MyRedisCache myRedisCache;
public MyRedisCache getMyRedisCache() {
return myRedisCache;
}
public void setMyRedisCache(MyRedisCache myRedisCache) {
this.myRedisCache = myRedisCache;
}
public MyCacheTemplate getMyCacheTemplate() {
return myCacheTemplate;
}
public void setMyCacheTemplate(MyCacheTemplate myCacheTemplate) {
this.myCacheTemplate = myCacheTemplate;
}
@Override
public Cache getCache(String name) {
//多级缓存实现
if(name.equals(myCacheTemplate.getName())){
return myCacheTemplate;
}
return null;
}
@Override
public Collection getCacheNames() {
return null;
}
}
自定义Cache实现:
package com.zyc.zspringboot.cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.Cache;
import org.springframework.cache.support.SimpleValueWrapper;
import org.springframework.data.redis.cache.RedisCacheElement;
import org.springframework.data.redis.cache.RedisCacheKey;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.core.RedisTemplate;
import java.util.concurrent.Callable;
/**
* @author zyc-admin
* @data 2018-03-19 17:15
**/
public class MyCacheTemplate implements Cache {
private static final Logger logger= LoggerFactory.getLogger(MyCacheTemplate.class);
private CacheManager ehCacheManager;
private RedisCacheManager redisCacheManager;
private RedisTemplate redisTemplate;
public CacheManager getEhCacheManager() {
return ehCacheManager;
}
public void setEhCacheManager(CacheManager ehCacheManager) {
this.ehCacheManager = ehCacheManager;
}
public RedisCacheManager getRedisCacheManager() {
return redisCacheManager;
}
public void setRedisCacheManager(RedisCacheManager redisCacheManager) {
this.redisCacheManager = redisCacheManager;
}
public RedisTemplate getRedisTemplate() {
return redisTemplate;
}
public void setRedisTemplate(RedisTemplate redisTemplate) {
this.redisTemplate = redisTemplate;
}
private String name;
@Override
public String getName() {
return name;
}
//自己添加set方法,实现Cache本身无此方法
public void setName(String name){
this.name=name;
}
@Override
public Object getNativeCache() {
return null;
}
@Override
public ValueWrapper get(Object key) {
ehCacheManager=CacheManager.getCacheManager("ec");
if(ehCacheManager!=null){
net.sf.ehcache.Cache myEhcache = ehCacheManager.getCache(getName());
logger.info("取数据ehcache库===key:{}",key);
if(myEhcache.get(key)!=null){
ValueWrapper v=new SimpleValueWrapper(myEhcache.get(key).getObjectValue());
return v;
}
}
Cache myRedis = redisCacheManager.getCache(getName());
if(myRedis!=null){
logger.info("取数据reids库===key:{}",key);
if(myRedis.get(key)!=null){
RedisCacheElement vr=new RedisCacheElement(new RedisCacheKey(key),myRedis.get(key).get());
return vr;
}
}
return null;
}
@Override
public T get(Object key, Class type) {
System.out.println(key+"======================="+type);
return null;
}
@Override
public T get(Object key, Callable valueLoader) {
return null;
}
@Override
public void put(Object key, Object value) {
ehCacheManager=CacheManager.getCacheManager("ec");
if(ehCacheManager!=null){
net.sf.ehcache.Cache myEhcache = ehCacheManager.getCache(getName());
Element e=new Element(key,value);
logger.info("插入ehcache库===key:{},value:{}",key,value);
myEhcache.put(e);
}
Cache myRedis = redisCacheManager.getCache(getName());
if(myRedis!=null){
logger.info("插入reids库===key:{},value:{}",key,value);
myRedis.put(key,value);
}
System.out.println("cha ru key "+ key);
}
@Override
public ValueWrapper putIfAbsent(Object key, Object value) {
return null;
}
@Override
public void evict(Object key) {
Cache myRedis = redisCacheManager.getCache(getName());
if(myRedis!=null){
logger.info("删除reids库===key:{}",key);
myRedis.evict(key);
}
ehCacheManager=CacheManager.getCacheManager("ec");
if(ehCacheManager!=null){
net.sf.ehcache.Cache myEhcache = ehCacheManager.getCache(getName());
logger.info("删除ehcache库===key:{}",key);
if(myEhcache.isKeyInCache(key)){
myEhcache.remove(key);
}
}
System.out.println("删除 key "+ key);
}
@Override
public void clear() {
Cache myRedis = redisCacheManager.getCache(getName());
myRedis.clear();
ehCacheManager=CacheManager.getCacheManager("ec");
if(ehCacheManager!=null) {
net.sf.ehcache.Cache myEhcache = ehCacheManager.getCache(getName());
myEhcache.removeAll();
}
}
}
使用spring cache 注解使用缓存如下:(在首次调用这个方法时,自定义缓存的put,get方法总是打印2次插入数据,2次取数据,暂时不知道什么原因,若有哪位大神知道,欢迎评论指点。)
@Cacheable(value = "j2CacheRedis", key = "'role:id:'+#id",unless ="#result == null")
//@Log(value = "获取数据并存入缓存")
public Role getRole(String id) {
// TODO Auto-generated method stub
return roleDao.getRole(id);
}
application.properties配置文件如下
#redis ------start-------
spring.redis.hostName=127.0.0.1
spring.redis.port=63791
spring.redis.timeOut=1000
spring.redis.maxIdle=10
spring.redis.maxWaitMillis=15000
spring.redis.testOnBorrow=true
spring.redis.testWhileIdle=false
ecache-shiro.xml配置文件如下(因本项目使用了shiro,所以Ehcache使用shiro的缓存配置文件)
整合过程遇到的问题: