Spring redis integration

1. Introduction to Redis
What is Redis?
redis is a key-value storage system. Similar to Memcached, it supports storage of relatively more value types, including string (string), list (linked list), set (collection), zset (sorted set – ordered collection) and hash (hash type). These data types all support push/pop, add/remove, intersection union and difference, and richer operations, and these operations are atomic. On this basis, redis supports sorting in various ways. Like memcached, data is cached in memory to ensure efficiency. The difference is that redis will periodically write updated data to disk or write modification operations to additional record files, and on this basis achieve master-slave (master-slave) synchronization.
What are the characteristics?
(1) The Redis database is completely in-memory and uses disk only for persistence.
(2) Compared with many key-value data stores, Redis has a richer set of data types.
(3) Redis can replicate data to any number of slave servers.
Redis advantage?
(1) Extremely fast: Redis is very fast, can execute about 110,000 collections per second, and about 81,000+ records per second.
(2) Supports rich data types: Redis supports most data types like lists, sets, sorted sets, and hashes that most developers already know. This makes it very easy to solve a wide variety of problems because we know which problems are better handled by the type of data it has.
(3) Operations are atomic: All Redis operations are atomic, which guarantees that if two clients access the Redis server at the same time, the updated value will be obtained.
(4) Multifunctional utility: Redis is a multifunctional tool that can be used in multiple uses such as caching, messaging, queues (Redis natively supports publish/subscribe), any short-lived data, applications such as web application sessions , page hit count, etc.
Disadvantages of Redis?
(1) Single thread ( 2 )
Memory     consumption <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 --> 2. Add the following configuration to the configuration bean in application.xml






<!-- jedis 配置 -->     <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig" >           <property name="maxIdle" value="${redis.maxIdle}" />           <property name="maxWaitMillis" value="${redis.maxWait}" />           <property name="testOnBorrow" value="${redis.testOnBorrow}" />     </bean >    <!-- redis服务器中心 -->     <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="${redis.password}" />           <property name="timeout" value="${redis.timeout}" ></property>     </bean >     <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate" >           <property name="connectionFactory" ref="connectionFactory" />           <property name="keySerializer" >               <bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />           </property>           <property name="valueSerializer" >               <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" />           </property>     </bean >       <!-- cache配置 -->     <bean id="methodCacheInterceptor" class="com.mucfc.msm.common.MethodCacheInterceptor" >           <property name="redisUtil" ref="redisUtil" />     </bean >     <bean id="redisUtil" class="com.mucfc.msm.common.RedisUtil" >           <property name="redisTemplate" ref="redisTemplate" />     </bean >redisTemplate" />     </bean >redisTemplate" />     </bean >
The configuration file redis and some configuration data redis.properties are as follows:
#redis center redis.host=10.75.202.11 redis.port=6379 redis.password=123456 redis.maxIdle=100 redis.maxActive=300 redis.maxWait=1000 redis.testOnBorrow =true redis.timeout=100000 # Classes that do not need to be added to the cache targetNames=xxxRecordManager, xxxSetRecordManager, xxxStatisticsIdentificationManager # Methods that do not need to be cached methodNames= #Set the cache invalidation time com.service.impl.xxxRecordManager= 60 com.service.impl.xxxSetRecordManager = 60 defaultCacheExpireTime=3600 fep.local.cache.capacity =10000
To scan these properties files, add the following configuration to application.xml
<!-- Introduce properties configuration file--> <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations"> <list> <value>classpath: properties/*.properties</value> <!--If there are multiple configuration files, just continue to add them here--> </list> </property> </bean>
3. Some tool classes
(1 ) In
the bean above RedisUtil, RedisUtil is an 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 工具类 * */ public final class RedisUtil { private Logger logger = Logger.getLogger(RedisUtil.class); private RedisTemplate<Serializable, Object> redisTemplate;  /**   * 批量删除对应的value   *   * @param keys   */ public void remove(final String... keys) {   for (String key : keys) {    remove(key);   } }  /**   * 批量删除key   *   * @param pattern   */ public void removePattern(final String pattern) {   Set<Serializable> keys = redisTemplate.keys(pattern);   if (keys.size() > 0)    redisTemplate.delete(keys);}  /**   * 删除对应的value   *   * @param key   */ public void remove(final String key) {   if (exists(key)) {    redisTemplate.delete(key);   } }  /**   * 判断缓存中是否有对应的value   *   * @param key   * @return   */ public boolean exists(final String key) {   return redisTemplate.hasKey(key); }  /**   * 读取缓存   *   * @param key   * @return   */ public Object get(final String key) {   Object result = null;   ValueOperations<Serializable, Object> operations = redisTemplate     .opsForValue();   result = operations.get(key);   return result; }  /**   * 写入缓存   *   * @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; }  /**   * 写入缓存   *   * @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();    operations.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; } }Long expireTime) {   boolean result = false;   try {    ValueOperations<Serializable, Object> operations = redisTemplate      .opsForValue();    operations.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; } }Long expireTime) {   boolean result = false;   try {    ValueOperations<Serializable, Object> operations = redisTemplate      .opsForValue();    operations.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; } }redisTemplate) {   this.redisTemplate = redisTemplate; } }redisTemplate) {   this.redisTemplate = redisTemplate; } }
(2) MethodCacheInterceptor
section MethodCacheInterceptor, which is used to add different methods to judge if there is data in the cache, and fetch data from the cache. Otherwise, it is fetched from the database for the first time, and the result is 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); private RedisUtil redisUtil ; private List<String> targetNamesList; // service names not included in the cache private List<String> methodNamesList; // method names not included in the cache private Long defaultCacheExpireTime; // default cache expiration time private Long xxxRecordManagerTime; // private Long xxxSetRecordManagerTime; // /** * Initialize the class name and method name that do not need to be added to the cache */ public MethodCacheInterceptor() { try { File f = new File("D:\lunaJee-workspace\msm\msm_core\src\main\java\com\mucfc\msm\common\cacheConf.properties"); //The location of the configuration file is directly written to death, you need to modify InputStream in = new FileInputStream( f); // InputStream in = 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"));    // 创建list    targetNamesList = new ArrayList<String>(targetNames.length);    methodNamesList = new ArrayList<String>(methodNames.length);    Integer maxLen = targetNames.length > methodNames.length ? targetNames.length      : methodNames.length;    // 将不需要缓存的类名和方法名添加到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();   } }  @Override public Object invoke(MethodInvocation invocation) throws Throwable {   Object value = null;    String targetName = invocation.getThis().getClass().getName();   String methodName = invocation.getMethod().getName();   // 不需要缓存的内容   //if (!isAddCache(StringUtil.subStrForLastDot(targetName), methodName)) {   if (!isAddCache(targetName, methodName)) {    // 执行方法返回结果    return invocation.proceed();   }   Object[] arguments = invocation.getArguments();   String key = getCacheKey(targetName, methodName, arguments);   System.out.println(key);    try {    // 判断是否有缓存    if (redisUtil.exists(key)) {     return redisUtil.get(key);    }    // 写入缓存    value = invocation.proceed();    if (value != null) {     final String tkey = key;     final Object tvalue = value;     new Thread(new Runnable() {      @Override      public 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; }  /**   * 是否加入缓存   *   * @return   */ private boolean isAddCache(String targetName, String methodName) {   boolean flag = true;   if (targetNamesList.contains(targetName)     || methodNamesList.contains(methodName)) {    flag = false;   }   return flag; }  /**   * 创建缓存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 class or method that needs to be cached Add the following configuration
in application.xml, there are multiple classes or methods that can be configured with multiple
<!-- The class or method that needs to be added to the cache--> <bean id="methodCachePointCut" class= "org.springframework.aop.support.RegexpMethodPointcutAdvisor" > <property name="advice" > <ref local="methodCacheInterceptor" /> </property> <property name="patterns" > <list> <!-- Determine the regular Expression list --> <value>com.mucfc.msm.service.impl...*ServiceImpl.*</value> </list> </property> </bean>
5. Execution result:
write a simple The unit tests are 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("查找结果" + configSettUnit.getBusinessType());     //  localSecondFIFOCache.put("configSettUnit", configSettUnit.getBusinessType());   //  String string = localSecondFIFOCache.get("configSettUnit");        logger.info("查找结果" + string);} Second execution: the SQL statement printed in the database: A breakpoint is set in the MethodCacheInterceptor class, and then this method will be entered before each query and run in sequence
This is the process of executing the unit test for the first time:







Because the first time it is executed, it has already been written to the cache. So the second time, the data is directly fetched from the cache.

3. The results of the two fetches are compared to the addresses:
it is found that the two are not the same object, yes, yes. If Ehcache is used, then the memory address of the two will be the same. That's because the caching mechanism used by redis and ehcache is different. Ehcache is based on the memory usage cache of the local computer, so when using the cache to fetch data, it is directly fetched on the local computer. Converting to a java object will be the same memory address, and redis is on the computer with the redis service (usually another computer), so when the data is fetched and transferred to the local, it will correspond to a different memory address, So using == to compare will return false. But it does fetch from the cache, as we can see from the breakpoint above.
Reprinted from http://www.techweb.com.cn/network/system/2015-12-28/2247743.shtml

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326034551&siteId=291194637
Recommended