Spring boot Spring Cache implementation of multi-level cache, just according to their own ideas to achieve, if the reader has a better solution to the idea, welcome guidance
The spring cache implements multilevel caching in the following ways:
Add custom CacheManager, custom cache, implement multi-level cache operation in cache (addition and deletion)
The configuration class takes note of the red marked sections as follows:
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 January 23, 2018 * @Description: */@Configuration @EnableCachi Ng (mode = advicemode.proxy)//model property default proxy//Mode property, you can select the value Proxy and ASPECTJ. Proxy is used by default. When mode is proxy,//Only the cache method will take effect when it is called externally. This also means that if a cache method is called inside a pair//image, Springcache is not going to work. When mode is ASPECTJ, there will be no//this problem.
In addition, when using proxy, only the public method on the @cacheable will take effect.
If you want to use a method other than public, then change mode to ASPECTJ. @ConfigurationProperties (prefix = "Spring.redis")//Getter Setter method that uses @configurationproperties to implement attributes,// Prior to 1.5, the version needs to be activated using @enableconfigurationproperties on the startup class, and 1.5 directly on the configuration class using @component,// Since this class uses @configuration annotations to include @component it is not necessary to declare @component,//so that it can be used directly in other classes @Autowired directly into the class//extends Cachingconfigurersupport public class Redisconfig {private String hostName;
private int port;
private int timeOut; private int maxidle;//Maximum number of idle connections, default 8 private int maxwaitmillis;//The maximum number of milliseconds to wait for a connection when the private Boolean testonborrow;//gets the connection's
When checking validity, the default false private Boolean testwhileidle;//whether the idle check is valid, the default is 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;
The public void Settestonborrow (Boolean testonborrow) {this.testonborrow = Testonborrow;
} public boolean Istestwhileidle () {return testwhileidle;
The public void Settestwhileidle (Boolean testwhileidle) {this.testwhileidle = Testwhileidle; } @Bean ("Jedispoolconfig") public jedispoolconfig Jedispoolconfig () {jedispoolconfig jedispoolconfig = new JedisPoo
Lconfig ();
Jedispoolconfig.setmaxidle (Maxidle);
Jedispoolconfig.setmaxwaitmillis (Maxwaitmillis);
Jedispoolconfig.settestonborrow (TRUE);
Jedispoolconfig.settestwhileidle (FALSE);
return jedispoolconfig; } @Bean Public jedisconnectionfactory redisconnectionfactory (jedispoolconfig jedispoolconfig) {//If the cluster uses new Jedi
Sconnectionfactory (New//Redisclusterconfiguration ()), cluster configuration in redisclusterconfiguration, here omit specific configuration
Jedisconnectionfactory redisconnectionfactory = new Jedisconnectionfactory ();
Redisconnectionfactory.setpoolconfig (Jedispoolconfig); redisconnectionfactory.seThostname (HostName);
Redisconnectionfactory.setport (port);
Redisconnectionfactory.settimeout (TimeOut);
return redisconnectionfactory; }/** * Redistemplate configuration * * @param redisconnectionfactory * @return redistemplate */@Bean public Redistempl Ate<string, object> redistemplate (jedisconnectionfactory redisconnectionfactory) {RedisTemplate<String, Ob
ject> redistemplate = new redistemplate<> ();
Redistemplate.setconnectionfactory (redisconnectionfactory);
redisserializer<string> Redisserializer = new Stringredisserializer ();
Redistemplate.setkeyserializer (Redisserializer); jackson2jsonredisserializer<object> Jackson2jsonredisserializer = new//jackson2jsonredisserializer<
Object> (//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 Cache Manager * @param redistemplate * @return * * * @Bean public rediscachemanager Rediscachemanager (RedisT
Emplate<string, object> redistemplate) {Rediscachemanager CacheManager = new Rediscachemanager (redisTemplate); Number of seconds before expiration. Defaults to Unlimited (0) cachemanager.setdefaultexpiration (120);
Set Key-value timeout time list<string> cachenames = new arraylist<> ();
Cachenames.add ("Myredis");
Cachenames.add ("J2cacheredis");
Cachemanager.setcachenames (Cachenames);
return CacheManager; }/** * Spring cache Consolidation (Ehcache,redis) level two cache specific caches * @param rediscachemanager * @param redistemplate * @return * /@Bean Public MycacheteMplate mycachetemplate (Rediscachemanager rediscachemanager,redistemplate<string, Object> RedisTemplate) {
Mycachetemplate mycachetemplate=new mycachetemplate ();
Mycachetemplate.setrediscachemanager (Rediscachemanager);
Mycachetemplate.setredistemplate (redistemplate);
Mycachetemplate.setname ("J2cacheredis");
return mycachetemplate; }/** * Custom Redis Cache * @param rediscachemanager * @param redistemplate * @return * * * @Bean public Myrediscache Myrediscache (Rediscachemanager rediscachemanager,redistemplate<string,object> RedisTemplate) {MyRedisCache
Myrediscache=new Myrediscache ();
Custom attribute configuration cache name Myrediscache.setname ("Myredis");
Redis Cache Manager Myrediscache.setrediscachemanager (Rediscachemanager);
Redistemplate instance myrediscache.setredistemplate (redistemplate);
return myrediscache; }/** * Spring Cache Unified Cache Manager * @param mycachetemplate * @param myrediscache * @return * * * @Bean @Primary Pub Lic CacheManager CacheManager (mycachetemplate Mycachetemplate,myrediscache myrediscache) {Mycachemanager cachemanager=new mycachemanager ();
Cachemanager.setmycachetemplate (mycachetemplate);
Cachemanager.setmyrediscache (Myrediscache);
return CacheManager; }//Integration Ehcache @Bean public Ehcachecachemanager Ehcachecachemanager () {Ehcachecachemanager Ehcachecachemanager
= New Ehcachecachemanager (Ehcachemanagerfactorybean (). GetObject ());
return ehcachecachemanager; } @Bean Public Ehcachemanagerfactorybean Ehcachemanagerfactorybean () {Ehcachemanagerfactorybean cacheManagerFacto
Rybean = new Ehcachemanagerfactorybean ();
Here for the time being borrow Shiro ehcache configuration file Resource r=new classpathresource ("Ehcache-shiro.xml");
Cachemanagerfactorybean.setconfiglocation (R);
Cachemanagerfactorybean.setshared (TRUE);
return Cachemanagerfactorybean;
}
}
The Custom CacheManager is as follows:
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) {
//multilevel Cache implementation
if (Name.equals ( Mycachetemplate.getname ())) {
return mycachetemplate;
}
return null;
}
@Override public
collection<string> getcachenames () {
return null;
}
}
Custom Cache implementations:
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<string, object> 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<string, Object> getredistemplate () {return redistemplate; } public void Setredistemplate (redistemplate<string, object> redistemplate) {this.redistemplate = RedisTemplate
;
} private String name;
@Override public String GetName () {return name;
}//Add the Set method yourself, implement the cache itself without this method 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 ("Fetch Data Ehcache library ===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 ("Fetch Data Reids library ===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> T get (Object key, class<t> type) {System.out.println (key+ "=======================
"+type);
return null;
} @Override Public <T> T get (Object key, callable<t> 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 ("Insert Ehcache Library ===key:{},value:{}", Key,value);
Myehcache.put (e); } Cache Myredis = Rediscachemanager.gEtcache (GetName ());
if (myredis!=null) {logger.info ("Insert Reids Library ===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 ("Delete reids library ===key:{}", key);
Myredis.evict (key);
} ehcachemanager=cachemanager.getcachemanager ("EC");
if (ehcachemanager!=null) {Net.sf.ehcache.Cache Myehcache = Ehcachemanager.getcache (GetName ());
Logger.info ("Delete ehcache library ===key:{}", key);
if (Myehcache.iskeyincache (key)) {Myehcache.remove (key);
}} System.out.println ("Delete 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 (); }
}
}
Using the spring cache annotations uses the following caches: (When this method is first called, the Put,get method of the custom cache is always printed 2 times to insert the data, 2 times to fetch the data, temporarily do not know what the reason, if any god knows, welcome comments pointing. )
@Cacheable (value = "J2cacheredis", key = "Role:id: ' + #id", unless = "#result = = null")
//@Log (value = "Get data and Cache") Public
Role getrole (String ID) {
//TODO auto-generated method stub
return roledao.getrole (ID);
}
The application.properties configuration file is as follows
#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
The Ecache-shiro.xml configuration file is as follows (Shiro is used for this project, so Ehcache uses the Shiro cache profile)
<? 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" name = "ec">
<diskStore path = "java.io.tmpdir" /> <!-cache storage directory (this directory is placed in the system's default cache directory), or "D: / cache" java.io.tmpdir->
<defaultCache
maxElementsInMemory = "10000"
eternal = "false"
timeToIdleSeconds = "120"
timeToLiveSeconds = "120"
overflowToDisk = "true"
maxElementsOnDisk = "10000000"
diskPersistent = "false"
diskExpiryThreadIntervalSeconds = "120"
memoryStoreEvictionPolicy = "LRU"
/>
<!-->
<cache name = "j2CacheRedis"
maxElementsInMemory = "1000"
eternal = "false"
timeToIdleSeconds = "120"
timeToLiveSeconds = "140"
overflowToDisk = "false"
memoryStoreEvictionPolicy = "LRU" />
<!-
name: the unique identifier of the cache
maxElementsInMemory: the maximum number of cached objects in memory
maxElementsOnDisk: the maximum number of cache objects in the disk, if 0 is infinite
eternal: Whether the element is permanently valid. Once set, timeout will not work.
overflowToDisk: configure this property, when the number of elements in memory reaches maxElementsInMemory, Ehcache will write the elements to disk
timeToIdleSeconds: Set the allowed idle time of the Element before it expires. Only used when element is not permanently valid. Optional attribute. The default value is 0, which means the idle time is infinite.
timeToLiveSeconds: Sets the time allowed for the element to expire before it expires. The maximum time is between the creation time and the expiration time. Only used when element is not permanently valid, the default is 0. That is, the element lifetime is infinite
diskPersistent: Whether to cache virtual machine restart data
diskExpiryThreadIntervalSeconds: the interval between disk failure threads running, the default is 120 seconds
diskSpoolBufferSizeMB: This parameter sets the size of the buffer area of the DiskStore. The default is 30MB. Each cache should have its own buffer
memoryStoreEvictionPolicy: When the maxElementsInMemory limit is reached, Ehcache will clear the memory according to the specified policy. The default policy is LRU (Least Recently Used). You can set it to FIFO (First In First Out) or LFU (Less Used)
->
</ ehcache>
Problems encountered in the integration process:
1 failed while creating CacheManager bean
WORKAROUND: You may have multiple CacheManager configured, make sure that you do not have duplicate names, and add @Primary annotations on the custom CacheManager
Custom CacheManager to implement the CacheManager interface,
Be careful not to inherit the Org.springframework.cache.support.AbstractCacheManager class to implement your own CacheManager
2 Create Ehcachecachemanager failed
WORKAROUND: See if your ehcachecachemanager is in conflict with Shiro's Ehcache cache.
EhCache version 2.5, the JVM typically only has EhCache instances.
3 Method Cache invalidation for internal method calls with spring cache annotations
Workaround: Spring cache relies on AOP, using Aopcontext.currentproxy (). Your method,
You need to expose the proxy object to add annotations before using @EnableAspectJAutoProxy (exposeproxy=true,proxytargetclass=true)
Exposeproxy: Exposing proxy objects, Proxytargetclass forcing use of Cglib proxy