Spring boot spring cacheを使用したマルチレベルキャッシュの統合(EhCache,Redis)

16698 ワード

Spring boot spring cacheマルチレベルキャッシュを実現
ただ自分の思想によって実現して、もし読者がもっと良い解決の構想があるならば、指摘を歓迎します
Spring cacheのマルチレベルキャッシュの実現の考え方は以下の通りである.
カスタムCacheManager、カスタムCacheを追加し、Cacheでマルチレベルキャッシュの操作を実現(添削)
クラスを構成するには、次の注意事項を示します.
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 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);
		// redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
		JdkSerializationRedisSerializer jdkSerializationRedisSerializer = new JdkSerializationRedisSerializer();
		redisTemplate.setValueSerializer(jdkSerializationRedisSerializer);
		return redisTemplate;
	}

	/**
	 * redis     
	 * @param redisTemplate
	 * @return
	 */
	@Bean
	public RedisCacheManager redisCacheManager(RedisTemplate redisTemplate) {
		RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);
		// Number of seconds before expiration. Defaults to unlimited (0)
		cacheManager.setDefaultExpiration(120); //  key-value    
		List cacheNames = new ArrayList<>();
		cacheNames.add("myRedis");
		cacheNames.add("j2CacheRedis");
		cacheManager.setCacheNames(cacheNames);
		return cacheManager;
	}

	/**
	 * spring cache  (EhCache,Redis)      Cache
	 * @param redisCacheManager
	 * @param redisTemplate
	 * @return
	 */
	@Bean
	public MyCacheTemplate myCacheTemplate(RedisCacheManager redisCacheManager,RedisTemplate redisTemplate){
		MyCacheTemplate myCacheTemplate=new MyCacheTemplate();
		myCacheTemplate.setRedisCacheManager(redisCacheManager);
		myCacheTemplate.setRedisTemplate(redisTemplate);
		myCacheTemplate.setName("j2CacheRedis");
		return myCacheTemplate;
	}

	/**
	 *    redis  
	 * @param redisCacheManager
	 * @param redisTemplate
	 * @return
	 */
	@Bean
	public MyRedisCache myRedisCache(RedisCacheManager redisCacheManager,RedisTemplate redisTemplate){
		MyRedisCache myRedisCache=new MyRedisCache();
		//           
		myRedisCache.setName("myRedis");
		//redis     
		myRedisCache.setRedisCacheManager(redisCacheManager);
		//redisTemplate   
		myRedisCache.setRedisTemplate(redisTemplate);
		return myRedisCache;
	}

	/**
	 * spring cache        
	 * @param myCacheTemplate
	 * @param myRedisCache
	 * @return
	 */
	@Bean
	@Primary
	public CacheManager cacheManager(MyCacheTemplate myCacheTemplate,MyRedisCache myRedisCache){
		MyCacheManager cacheManager=new MyCacheManager();
		cacheManager.setMyCacheTemplate(myCacheTemplate);
		cacheManager.setMyRedisCache(myRedisCache);
		return cacheManager;
	}

	 //   ehcache
	 @Bean
	 public EhCacheCacheManager ehCacheCacheManager() {
		 EhCacheCacheManager ehCacheCacheManager = new EhCacheCacheManager(ehCacheManagerFactoryBean().getObject());
		  return ehCacheCacheManager;
	 }


	 @Bean
	 public EhCacheManagerFactoryBean ehCacheManagerFactoryBean() {
	 EhCacheManagerFactoryBean cacheManagerFactoryBean = new
	 EhCacheManagerFactoryBean();
	 //      shiro ehcache    
	 Resource r=new ClassPathResource("ehcache-shiro.xml");
	 cacheManagerFactoryBean.setConfigLocation(r);
	 cacheManagerFactoryBean.setShared(true);
	 return cacheManagerFactoryBean;
	 }

}

カスタム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注釈を使用してキャッシュを使用すると、以下のようになります.
@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のキャッシュプロファイルを使用しています)



 
    

    
    

    
  
統合プロセスで発生した問題:
1
cacheManager beanの作成に失敗しました
解決方法:複数のcacheManagerを構成して、名前が重複しないことを確認し、カスタムのcacheManagerに@Primary注記を追加する可能性があります.
カスタムCacheManager CacheManagerインタフェースを実装するには、
注意orgを継承しないでください.springframework.cache.support.AbstraactCacheManagerというクラスで独自のCacheManagerを実現
2
EhCacheCacheManagerの作成に失敗しました
解決策:EhCacheCacheManagerがshiroのEhCacheキャッシュと競合しているかどうかを確認します.
EhCache 2.5バージョン以上では、jvmには一般的にEhCacheインスタンスしか存在しません.
3
内部メソッド呼び出しspring cache注釈付きメソッドキャッシュが無効になりました
解決方法:spring cacheはaopに依存し、AopContextを使用する.currentProxy().あなたの方法は
使用する前に、プロキシオブジェクトを露出して注記@EnableAspectJAutoProxy(exposeProxy=true、proxyTargetClass=true)を追加する必要があります.
exposeProxy:プロキシオブジェクトを露出し、proxyTargetClassはcglibプロキシを強制的に使用する