Summary: This article describes how to configure Redis in spring and, through the idea of AOP in spring, cut the cached method in front of a class or method that needs to go into the cache.
First, Redis Introduction
What is Redis?
Redis is a key-value storage system. Similar to memcached, it supports storing more value types, including string (string), list (linked list), set (set), Zset (sorted set– ordered collection), and hash (hash type). These data types support Push/pop, Add/remove, and intersection-set and difference sets, and richer operations, and these operations are atomic. Based on this, Redis supports sorting in a variety of different ways. As with memcached, data is cached in memory to ensure efficiency. The difference is that Redis periodically writes the updated data to disk or writes the modified operation to the appended record file, and Master-slave (Master-Slave) synchronization is implemented on this basis.
What is the characteristic of it?
(1) The Redis database is completely in memory and uses disk for persistence only.
(2) Redis has a rich set of data types compared to many key-value data stores.
(3) Redis can replicate data to any number of slave servers.
What is the Redis advantage?
(1) Unusually fast: Redis is very fast and can perform about 110,000 episodes per second, about 81000 + records per second.
(2) Support for rich data types: Redis support Most developers already know like lists, collections, ordered collections, hash data types. This makes it very easy to solve a wide variety of problems because we know which issues are better than the data types that can be handled through it.
(3) Operations are atomic: All Redis operations are atomic, which ensures that Redis servers accessed by two clients will get the updated values.
(4) Multifunction utility: Redis is a multi-utility tool that can be used in multiple uses such as cache, message, queue (Redis native support publish/subscribe), any transient data, applications such as Web application sessions, Web page hits count etc.
Redis drawbacks?
(1) Single thread
(2) Memory consumption
Ii. Examples of Use
This article uses maven+eclipse+sping
1. Introduction of JAR Package
<!--Redis start--><dependency><groupid>org.springframework.data</groupid><artifactid >spring-data-redis</artifactId><version>1.6.1.RELEASE</version></dependency>< dependency><groupid>redis.clients</groupid><artifactid>jedis</artifactid>< Version>2.7.3</version></dependency> <!--Redis End-to-
2. Configure Bean
Add the following configuration in Application.xml
<!--Jedis configuration--<bean id= "Poolconfig" class= "Redis.clients.jedis.JedisPoolConfig" > <propert Y name= "Maxidle" value= "${redis.maxidle}"/> <property name= "Maxwaitmillis" value= "${redis.maxwait}"/> <property name= "Testonborrow" value= "${redis.testonborrow}"/> </bean > <!--redis Server Center--> ; <bean id= "ConnectionFactory" class= "Org.springframework.data.redis.connection.jedis.JedisConnectionFactory" > <property name= "poolconfig" ref= "Poolconfig"/> <property name= "port" value= "${redis.port} "/> <property name=" hostName "value=" ${redis.host} "/> <property name=" password "value=" ${r Edis.password} "/> <property name=" Timeout "value=" ${redis.timeout} "></property> </bean ; <bean id= "Redistemplate" class= "org.springframework.data.redis.core.RedisTemplate" > <property name= "con Nectionfactory "ref=" conNectionfactory "/> <property name=" Keyserializer "> <bean class=" Org.springframework.dat A.redis.serializer.stringredisserializer "/> </property> <property name=" ValueSerializer "&G T <bean class= "Org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/> </property> ; </bean > <!--cache configuration-<bean id= "Methodcacheinterceptor" class= "Com.mucfc.msm.common.MethodCacheI Nterceptor "> <property name=" redisutil "ref=" Redisutil "/> </bean > <bean id=" Redisutil " class= "Com.mucfc.msm.common.RedisUtil" > <property name= "redistemplate" ref= "Redistemplate"/> </ Bean >
Where configuration file Redis Some configuration data redis.properties as follows:
#redis中心redis. host=10.75.202.11redis.port=6379redis.password=123456redis.maxidle=100redis.maxactive= 300redis.maxwait=1000redis.testonborrow=trueredis.timeout=100000# does not need to join the cached class Targetnames=xxxrecordmanager, xxxsetrecordmanager,xxxstatisticsidentificationmanager# does not require a cached method methodnames=# Set cache expiration Time com.service.impl.xxxrecordmanager= 60com.service.impl.xxxsetrecordmanager= 60defaultcacheexpiretime= 3600fep.local.cache.capacity =10000
To sweep these properties files, add the following configuration to the Application.xml
<!--introducing the Properties profile-- <bean id= "Propertyconfigurer" class= " Org.springframework.beans.factory.config.PropertyPlaceholderConfigurer "> <property name=" Locations " > <list> <value>classpath:properties/*.properties</value> <!--If you have more than one configuration file, Just keep adding here-- </list> </property> </bean>
3. Some tool classes
(1) Redisutil
In the above Bean, Redisutil is the instance used to cache and remove data
Package Com.mucfc.msm.common;import Java.io.serializable;import Java.util.set;import java.util.concurrent.TimeUnit ; Import Org.apache.log4j.logger;import Org.springframework.data.redis.core.redistemplate;import org.springframework.data.redis.core.valueoperations;/** * Redis Cache Tool Class * */public final class Redisutil {private Logge R logger = Logger.getlogger (redisutil.class);p rivate redistemplate<serializable, object> redisTemplate;/** * Bulk delete the corresponding value * * @param keys */public void Remove (final String ... keys) {for (string Key:keys) {remove (key);}} /** * Bulk Delete key * * @param pattern */public void Removepattern (final String pattern) {set<serializable> keys = RedisT Emplate.keys (pattern); if (keys.size () > 0) redistemplate.delete (keys); /** * Delete the corresponding value * * @param key */public void Remove (final String key) {if (Exists (key)) {Redistemplate.delete (key);}} /** * Determine if there is a corresponding value in the cache * * @param key * @return */public Boolean exists (final String key) {return Redistemplate.haskey (ke y);}/** * Read Cache * * @param key * @return */public object Get (Final String key) {object result = NULL; Valueoperations<serializable, object> operations = Redistemplate.opsforvalue (); result = Operations.get (key); return result;} /** * Write Cache * * @param key * @param value * @return */public Boolean set (Final String key, Object value) {Boolean result = false;try {valueoperations<serializable, object> operations = Redistemplate.opsforvalue (); Operations.set (Key, value); result = true;} catch (Exception e) {e.printstacktrace ();} return result;} /** * Write Cache * * @param key * @param value * @return */public Boolean set (Final String key, Object value, Long expiretime) {Boolean result = False;try {valueoperations<serializable, object> operations = Redistemplate.opsforvalue (); O Perations.set (key, value); Redistemplate.expire (Key, Expiretime, timeunit.seconds); result = true;} catch (Exception e) {e.printstacktrace ();} return result;} public void Setredistemplate (redistemplate<serializable, OBJEct> redistemplate) {this.redistemplate = Redistemplate;}}
(2) Methodcacheinterceptor
Tangent Methodcacheinterceptor, which is used to give different methods to add judgment if the cache exists data, fetch data from the cache. Otherwise, the first time it is taken from the database and the results are saved to the cache.
Package Com.mucfc.msm.common;import Java.io.file;import Java.io.fileinputstream;import java.io.InputStream;import Java.util.arraylist;import Java.util.list;import Java.util.properties;import Org.aopalliance.intercept.methodinterceptor;import Org.aopalliance.intercept.methodinvocation;import Org.apache.log4j.logger;public class Methodcacheinterceptor implements Methodinterceptor {private Logger Logger = Logger.getlogger (methodcacheinterceptor.class);p rivate redisutil redisutil;private List<String> Targetnameslist; Service name not added to the cache private list<string> methodnameslist; Method name not added to cache private Long defaultcacheexpiretime; Cache default Expiration time private long xxxrecordmanagertime; Private Long Xxxsetrecordmanagertime; * * Initialize read does not need to join the cache class name and method name */public Methodcacheinterceptor () {try {file F = new File ("D:\\lunajee-workspace\\msm\\msm_ Core\\src\\main\\java\\com\\mucfc\\msm\\common\\cacheconf.properties "); The configuration file location is written directly to die, there is a need to modify the next inputstream in = new FileInputStream (f); InputStreamin = GetClass (). getClassLoader (). getResourceAsStream (//"d:\\lunajee-workspace\\msm\\msm_core\\src\\main\\java\\ Com\\mucfc\\msm\\common\\cacheconf.properties "); Properties p = new properties ();p. Load (in);//split string string[] Targetnames = P.getproperty ("Targetnames"). Split (","); string[] Methodnames = P.getproperty ("Methodnames"). Split (",");//Load Expiration time Setting Defaultcacheexpiretime = long.valueof ( P.getproperty ("Defaultcacheexpiretime")); xxxrecordmanagertime = long.valueof (P.getproperty (" Com.service.impl.xxxRecordManager ")); xxxsetrecordmanagertime = long.valueof (P.getproperty (" Com.service.impl.xxxSetRecordManager "));//Create listtargetnameslist = new Arraylist<string> (targetnames.length) ; methodnameslist = new arraylist<string> (methodnames.length); Integer maxlen = targetnames.length > Methodnames.length? Targetnames.length:methodnames.length;//adds the class name and method name that do not need to be cached to list for (int i = 0; i < MaxLen; i++) {if (I < targetnames . length) {Targetnameslist.add (targetnames[i]);} if (I < MethodnamEs.length) {Methodnameslist.add (methodnames[i]);}} catch (Exception e) {e.printstacktrace ();}} @Overridepublic object Invoke (Methodinvocation invocation) throws Throwable {Object value = null; String targetName = Invocation.getthis (). GetClass (). GetName (); String methodName = Invocation.getmethod (). GetName ();//content not required for caching//if (!isaddcache (Stringutil.substrforlastdot ( TargetName) (MethodName)) {if (!isaddcache (TargetName, MethodName)) {//Execute method returns the result return Invocation.proceed ();} object[] arguments = invocation.getarguments (); String key = Getcachekey (TargetName, methodName, arguments); SYSTEM.OUT.PRINTLN (key); try {//To determine if there is a cache if (Redisutil.exists (key)) {return redisutil.get (key);} Write Cache value = Invocation.proceed (), if (value! = null) {final String TKey = key;final Object TValue = value;new Thread (new Runnable () {@Overridepublic void run () {if (Tkey.startswith ("Com.service.impl.xxxRecordManager")) {Redisutil.set ( TKey, TValue, xxxrecordmanagertime);} else if (Tkey.startswith ("Com.service.impl.xxxSetRecOrdmanager ")) {Redisutil.set (TKey, TValue, xxxsetrecordmanagertime);} else {Redisutil.set (TKey, TValue, defaultcacheexpiretime);}}). Start ();}} catch (Exception e) {e.printstacktrace (); if (value = = null) {return invocation.proceed ();}} return value;} /** * Whether to add cache * * @return */private boolean Isaddcache (String targetName, String methodName) {Boolean flag = True;if (Targ Etnameslist.contains (targetName) | | Methodnameslist.contains (MethodName)) {flag = false;} return flag;} /** * Create Cache Key * * @param targetName * @param methodName * @param arguments */private string Getcachekey (String targetName, String methodname,object[] arguments) {StringBuffer SBU = new StringBuffer (); Sbu.append (TargetName). Append ("_"). Append (MethodName); if (arguments! = null) && (arguments.length! = 0)) {for (int i = 0; i < arguments.length; I + +) {Sbu.append ("_"). Append (Arguments[i]);}} return sbu.tostring ();} public void Setredisutil (Redisutil redisutil) {this.redisutil = Redisutil;}}
4. Configure the classes or methods that need to be cached
In Application.xml, there are several classes or methods that can be configured to configure multiple
<!--need to add a cached class or method-- <bean id= "methodcachepointcut" class= " Org.springframework.aop.support.RegexpMethodPointcutAdvisor "> <property name=" Advice "> <ref Local= "Methodcacheinterceptor"/> </property> <property name= "Patterns" > <list> <!--determine the list of regular expressions-- <value>com\.mucfc\.msm\.service\.impl\...*serviceimpl.*</value > </list> </property> </bean >
5. Execution Result:
Write a simple unit test as follows:
@Test public void Getsettunitbysettunitidtest () { String systemid = "CES"; String Merchantid = "133"; Settunit configsettunit = Settunitservice.getsettunitbysettunitid (SystemID, Merchantid, "ESP"); Settunit configSettUnit1 = Settunitservice.getsettunitbysettunitid (SystemID, Merchantid, "ESP"); Boolean flag= (Configsettunit = = configSettUnit1); System.out.println (configsettunit); Logger.info ("Find results" + configsettunit.getbusinesstype ()); localsecondfifocache.put ("Configsettunit", Configsettunit.getbusinesstype ()); string string = Localsecondfifocache.get ("Configsettunit");// Logger.info ("Find results" + String); }
This is the first time a unit test is performed:
Methodcacheinterceptor this class to break points, and then every time before each query will go into this method
Run in sequence and find no cache, so we'll go straight to the database.
The SQL statement that was printed out:
Second execution:
Because the cache was written the first time it was executed. So the second time to fetch the data directly from the cache
3, take two times the results of the comparison of the address:
Found two not the same object, yes, yes. If you use Ehcache, the memory address of both will be the same. That's because the caching mechanism used by Redis and Ehcache is not the same. Ehcache is based on the local computer's memory usage cache, so the cache is used to fetch data directly on the local computer. The conversion to Java object will be the same memory address, and redis it is on the computer with Redis service (usually another computer), so when the data is transferred to the local, will correspond to a different memory address, so use = = to compare will return false. But it is actually taken from the cache, which we can see from the breakpoint above.
Redis consolidation Spring uses cached instances together