spring-data-redis分布式

本文转载http://hbxflihua.iteye.com/blog/2383495

1、引入spring-data-redis依赖的jar 包

Xml代码   收藏代码
  1. <dependency>  
  2.             <groupId>org.springframework.data</groupId>  
  3.             <artifactId>spring-data-redis</artifactId>  
  4.             <version>1.7.1.RELEASE</version>  
  5.             <exclusions>  
  6.                 <exclusion>  
  7.                     <artifactId>spring-tx</artifactId>  
  8.                     <groupId>org.springframework</groupId>  
  9.                 </exclusion>  
  10.                 <exclusion>  
  11.                     <artifactId>spring-context-support</artifactId>  
  12.                     <groupId>org.springframework</groupId>  
  13.                 </exclusion>  
  14.                 <exclusion>  
  15.                     <artifactId>spring-core</artifactId>  
  16.                     <groupId>org.springframework</groupId>  
  17.                 </exclusion>  
  18.                 <exclusion>  
  19.                     <artifactId>spring-aop</artifactId>  
  20.                     <groupId>org.springframework</groupId>  
  21.                 </exclusion>  
  22.                 <exclusion>  
  23.                     <artifactId>spring-context</artifactId>  
  24.                     <groupId>org.springframework</groupId>  
  25.                 </exclusion>  
  26.             </exclusions>  
  27.         </dependency>  
  28.         <dependency>  
  29.             <groupId>redis.clients</groupId>  
  30.             <artifactId>jedis</artifactId>  
  31.             <version>2.8.1</version>  
  32.         </dependency>  

2、添加缓存注解

Java代码   收藏代码
  1. package com.huatech.common.annotation;  
  2.   
  3. import java.lang.annotation.Documented;  
  4. import java.lang.annotation.ElementType;  
  5. import java.lang.annotation.Inherited;  
  6. import java.lang.annotation.Retention;  
  7. import java.lang.annotation.RetentionPolicy;  
  8. import java.lang.annotation.Target;  
  9. /** 
  10.  * 添加缓存 
  11.  * @author lh 
  12.  * 
  13.  */  
  14. @Target({ElementType.METHOD})  
  15. @Retention(RetentionPolicy.RUNTIME)  
  16. @Inherited  
  17. @Documented  
  18. public @interface Cacheable {  
  19.   
  20.     /** 
  21.      * 缓存key 
  22.      * @return 
  23.      */  
  24.     public String key() default "";   
  25.       
  26.     /** 
  27.      * 缓存时效,默认无限期 
  28.      * @return 
  29.      */  
  30.     public long expire() default 0L;   
  31.   
  32. }  
Java代码   收藏代码
  1. package com.huatech.common.annotation;  
  2.   
  3. import java.lang.annotation.Documented;  
  4. import java.lang.annotation.ElementType;  
  5. import java.lang.annotation.Inherited;  
  6. import java.lang.annotation.Retention;  
  7. import java.lang.annotation.RetentionPolicy;  
  8. import java.lang.annotation.Target;  
  9. /** 
  10.  * 缓存清除 
  11.  * @author lh 
  12.  * @version 3.0 
  13.  * @since 2016-8-28 
  14.  * 
  15.  */  
  16. @Target({ElementType.METHOD})  
  17. @Retention(RetentionPolicy.RUNTIME)  
  18. @Inherited  
  19. @Documented  
  20. public @interface CacheEvict {  
  21.       
  22.     /** 
  23.      * 缓存key数组 
  24.      * @return 
  25.      */  
  26.     String[] keys() default "";  
  27.     /** 
  28.      * 操作之间的缓存时间(秒) 
  29.      * @author  FangJun 
  30.      * @date 2016年9月9日 
  31.      * @return 默认0,不做限制 
  32.      */  
  33.     long interval() default 0;  
  34.       
  35. }  

 3、添加缓存操作工具类

Java代码   收藏代码
  1. package com.huatech.common.util;  
  2.   
  3. import java.lang.reflect.Field;  
  4. import java.lang.reflect.InvocationTargetException;  
  5. import java.lang.reflect.Method;  
  6. import java.lang.reflect.Modifier;  
  7. import java.lang.reflect.ParameterizedType;  
  8. import java.lang.reflect.Type;  
  9. import java.util.HashMap;  
  10. import java.util.Map;  
  11.   
  12. import org.apache.commons.lang3.ArrayUtils;  
  13. import org.apache.commons.lang3.StringUtils;  
  14. import org.apache.commons.lang3.Validate;  
  15. import org.slf4j.Logger;  
  16. import org.slf4j.LoggerFactory;  
  17.   
  18.   
  19. @SuppressWarnings("rawtypes")  
  20. public class ReflectionUtils {  
  21.   
  22.     private static final String SETTER_PREFIX = "set";  
  23.   
  24.     private static final String GETTER_PREFIX = "get";  
  25.   
  26.     private static final String CGLIB_CLASS_SEPARATOR = "$$";  
  27.       
  28.     private static Logger logger = LoggerFactory.getLogger(ReflectionUtils.class);  
  29.   
  30.     public static Object invokeGetMethod(Class<?> claszz, Object o, String name) {  
  31.         Object ret = null;  
  32.         try {  
  33.             Method method = claszz.getMethod("get" +  StringUtil.firstCharUpperCase(name));  
  34.             ret = method.invoke(o);  
  35.         } catch (Exception e) {  
  36.             logger.error(e.getMessage(),e);  
  37.         }  
  38.         return ret;  
  39.     }  
  40.       
  41.       
  42.     /** 
  43.      * 调用Getter方法. 
  44.      * 支持多级,如:对象名.对象名.方法 
  45.      */  
  46.     public static Object invokeGetter(Object obj, String propertyName) {  
  47.         Object object = obj;  
  48.         for (String name : StringUtils.split(propertyName, ".")){  
  49.             String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(name);  
  50.             object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {});  
  51.         }  
  52.         return object;  
  53.     }  
  54.   
  55.     /** 
  56.      * 调用Setter方法, 仅匹配方法名。 
  57.      * 支持多级,如:对象名.对象名.方法 
  58.      */  
  59.     public static void invokeSetter(Object obj, String propertyName, Object value) {  
  60.         Object object = obj;  
  61.         String[] names = StringUtils.split(propertyName, ".");  
  62.         for (int i=0; i<names.length; i++){  
  63.             if(i<names.length-1){  
  64.                 String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(names[i]);  
  65.                 object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {});  
  66.             }else{  
  67.                 String setterMethodName = SETTER_PREFIX + StringUtils.capitalize(names[i]);  
  68.                 invokeMethodByName(object, setterMethodName, new Object[] { value });  
  69.             }  
  70.         }  
  71.     }  
  72.       
  73.     /** 
  74.      * 调用Setter方法(赋值) 
  75.      * @param claszz 
  76.      * @param o 
  77.      * @param name 
  78.      * @param argType 
  79.      * @param args 
  80.      * @return 
  81.      */  
  82.     public static Object invokeSetter(Class<?> claszz, Object o, String name, Class<?> argType, Object args) {  
  83.         Object ret = null;  
  84.         try {  
  85.             // 非 常量 进行反射  
  86.             if (!checkModifiers(claszz, name)) {  
  87.                 Method method = claszz.getMethod("set" + StringUtil.firstCharUpperCase(name), new Class[] { argType });  
  88.                 ret = method.invoke(o, new Object[] { args });  
  89.             }  
  90.         } catch (Exception e) {  
  91.             logger.error("claszz:{},name:{},argType:{},args:{}",claszz,name,argType, args);  
  92.         }  
  93.         return ret;  
  94.     }  
  95.   
  96.     /** 
  97.      * 直接读取对象属性值, 无视private/protected修饰符, 不经过getter函数. 
  98.      */  
  99.     public static Object getFieldValue(final Object obj, final String fieldName) {  
  100.         Field field = getAccessibleField(obj, fieldName);  
  101.   
  102.         if (field == null) {  
  103.             throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + obj + "]");  
  104.         }  
  105.   
  106.         Object result = null;  
  107.         try {  
  108.             result = field.get(obj);  
  109.         } catch (IllegalAccessException e) {  
  110.             logger.error("不可能抛出的异常{}", e.getMessage());  
  111.         }  
  112.         return result;  
  113.     }  
  114.   
  115.     /** 
  116.      * 直接设置对象属性值, 无视private/protected修饰符, 不经过setter函数. 
  117.      */  
  118.     public static void setFieldValue(final Object obj, final String fieldName, final Object value) {  
  119.         Field field = getAccessibleField(obj, fieldName);  
  120.   
  121.         if (field == null) {  
  122.             throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + obj + "]");  
  123.         }  
  124.   
  125.         try {  
  126.             field.set(obj, value);  
  127.         } catch (IllegalAccessException e) {  
  128.             logger.error("不可能抛出的异常:{}", e.getMessage());  
  129.         }  
  130.     }  
  131.   
  132.     /** 
  133.      * 直接调用对象方法, 无视private/protected修饰符. 
  134.      * 用于一次性调用的情况,否则应使用getAccessibleMethod()函数获得Method后反复调用. 
  135.      * 同时匹配方法名+参数类型, 
  136.      */  
  137.     public static Object invokeMethod(final Object obj, final String methodName, final Class<?>[] parameterTypes,  
  138.             final Object[] args) {  
  139.         Method method = getAccessibleMethod(obj, methodName, parameterTypes);  
  140.         if (method == null) {  
  141.             throw new IllegalArgumentException("Could not find method [" + methodName + "] on target [" + obj + "]");  
  142.         }  
  143.   
  144.         try {  
  145.             return method.invoke(obj, args);  
  146.         } catch (Exception e) {  
  147.             throw convertReflectionExceptionToUnchecked(e);  
  148.         }  
  149.     }  
  150.   
  151.     /** 
  152.      * 直接调用对象方法, 无视private/protected修饰符, 
  153.      * 用于一次性调用的情况,否则应使用getAccessibleMethodByName()函数获得Method后反复调用. 
  154.      * 只匹配函数名,如果有多个同名函数调用第一个。 
  155.      */  
  156.     public static Object invokeMethodByName(final Object obj, final String methodName, final Object[] args) {  
  157.         Method method = getAccessibleMethodByName(obj, methodName);  
  158.         if (method == null) {  
  159.             throw new IllegalArgumentException("Could not find method [" + methodName + "] on target [" + obj + "]");  
  160.         }  
  161.   
  162.         try {  
  163.             return method.invoke(obj, args);  
  164.         } catch (Exception e) {  
  165.             throw convertReflectionExceptionToUnchecked(e);  
  166.         }  
  167.     }  
  168.   
  169.     /** 
  170.      * 循环向上转型, 获取对象的DeclaredField, 并强制设置为可访问. 
  171.      *  
  172.      * 如向上转型到Object仍无法找到, 返回null. 
  173.      */  
  174.     public static Field getAccessibleField(final Object obj, final String fieldName) {  
  175.         Validate.notNull(obj, "object can't be null");  
  176.         Validate.notBlank(fieldName, "fieldName can't be blank");  
  177.         for (Class<?> superClass = obj.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()) {  
  178.             try {  
  179.                 Field field = superClass.getDeclaredField(fieldName);  
  180.                 makeAccessible(field);  
  181.                 return field;  
  182.             } catch (NoSuchFieldException e) {//NOSONAR  
  183.                 // Field不在当前类定义,继续向上转型  
  184.                 continue;// new add  
  185.             }  
  186.         }  
  187.         return null;  
  188.     }  
  189.   
  190.     /** 
  191.      * 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问. 
  192.      * 如向上转型到Object仍无法找到, 返回null. 
  193.      * 匹配函数名+参数类型。 
  194.      *  
  195.      * 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args) 
  196.      */  
  197.     public static Method getAccessibleMethod(final Object obj, final String methodName,  
  198.             final Class<?>... parameterTypes) {  
  199.         Validate.notNull(obj, "object can't be null");  
  200.         Validate.notBlank(methodName, "methodName can't be blank");  
  201.   
  202.         for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) {  
  203.             try {  
  204.                 Method method = searchType.getDeclaredMethod(methodName, parameterTypes);  
  205.                 makeAccessible(method);  
  206.                 return method;  
  207.             } catch (NoSuchMethodException e) {  
  208.                 // Method不在当前类定义,继续向上转型  
  209.                 continue;// new add  
  210.             }  
  211.         }  
  212.         return null;  
  213.     }  
  214.   
  215.     /** 
  216.      * 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问. 
  217.      * 如向上转型到Object仍无法找到, 返回null. 
  218.      * 只匹配函数名。 
  219.      *  
  220.      * 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args) 
  221.      */  
  222.     public static Method getAccessibleMethodByName(final Object obj, final String methodName) {  
  223.         Validate.notNull(obj, "object can't be null");  
  224.         Validate.notBlank(methodName, "methodName can't be blank");  
  225.   
  226.         for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) {  
  227.             Method[] methods = searchType.getDeclaredMethods();  
  228.             for (Method method : methods) {  
  229.                 if (method.getName().equals(methodName)) {  
  230.                     makeAccessible(method);  
  231.                     return method;  
  232.                 }  
  233.             }  
  234.         }  
  235.         return null;  
  236.     }  
  237.   
  238.     /** 
  239.      * 改变private/protected的方法为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。 
  240.      */  
  241.     public static void makeAccessible(Method method) {  
  242.         if ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers()))  
  243.                 && !method.isAccessible()) {  
  244.             method.setAccessible(true);  
  245.         }  
  246.     }  
  247.   
  248.     /** 
  249.      * 改变private/protected的成员变量为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。 
  250.      */  
  251.     public static void makeAccessible(Field field) {  
  252.         if ((!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers()) || Modifier  
  253.                 .isFinal(field.getModifiers())) && !field.isAccessible()) {  
  254.             field.setAccessible(true);  
  255.         }  
  256.     }  
  257.   
  258.     /** 
  259.      * 通过反射, 获得Class定义中声明的泛型参数的类型, 注意泛型必须定义在父类处 
  260.      * 如无法找到, 返回Object.class. 
  261.      * eg. 
  262.      * public UserDao extends HibernateDao<User> 
  263.      * 
  264.      * @param clazz The class to introspect 
  265.      * @return the first generic declaration, or Object.class if cannot be determined 
  266.      */  
  267.     @SuppressWarnings("unchecked")  
  268.     public static <T> Class<T> getClassGenricType(final Class clazz) {  
  269.         return getClassGenricType(clazz, 0);  
  270.     }  
  271.   
  272.     /** 
  273.      * 通过反射, 获得Class定义中声明的父类的泛型参数的类型. 
  274.      * 如无法找到, 返回Object.class. 
  275.      *  
  276.      * 如public UserDao extends HibernateDao<User,Long> 
  277.      * 
  278.      * @param clazz clazz The class to introspect 
  279.      * @param index the Index of the generic ddeclaration,start from 0. 
  280.      * @return the index generic declaration, or Object.class if cannot be determined 
  281.      */  
  282.     public static Class getClassGenricType(final Class clazz, final int index) {  
  283.   
  284.         Type genType = clazz.getGenericSuperclass();  
  285.   
  286.         if (!(genType instanceof ParameterizedType)) {  
  287.             logger.warn("{}'s superclass not ParameterizedType",clazz.getSimpleName());  
  288.             return Object.class;  
  289.         }  
  290.   
  291.         Type[] params = ((ParameterizedType) genType).getActualTypeArguments();  
  292.   
  293.         if (index >= params.length || index < 0) {  
  294.             logger.warn("Index: {}, Size of {}'s Parameterized Type: {}",index,clazz.getSimpleName(), params.length);  
  295.             return Object.class;  
  296.         }  
  297.         if (!(params[index] instanceof Class)) {  
  298.             logger.warn(" {} not set the actual class on superclass generic parameter",clazz.getSimpleName());  
  299.             return Object.class;  
  300.         }  
  301.   
  302.         return (Class) params[index];  
  303.     }  
  304.       
  305.     public static Class<?> getUserClass(Object instance) {  
  306.         if(instance == null){  
  307.             throw new RuntimeException("Instance must not be null");  
  308.         }  
  309.         Class clazz = instance.getClass();  
  310.         if (clazz != null && clazz.getName().contains(CGLIB_CLASS_SEPARATOR)) {  
  311.             Class<?> superClass = clazz.getSuperclass();  
  312.             if (superClass != null && !Object.class.equals(superClass)) {  
  313.                 return superClass;  
  314.             }  
  315.         }  
  316.         return clazz;  
  317.   
  318.     }  
  319.       
  320.     /** 
  321.      * 取得类中某个Field的类型名称 
  322.      * @param clazz 
  323.      * @param fieldName 
  324.      * @return 
  325.      */  
  326.     public static String getFieldTypeName(final Class clazz, String fieldName) {  
  327.         Field field = null;  
  328.         Class tclazz = clazz;  
  329.         do {  
  330.             try {  
  331.                 field = tclazz.getDeclaredField(fieldName);  
  332.             } catch (NoSuchFieldException e) {  
  333.                 tclazz = clazz.getSuperclass();  
  334.             } catch (SecurityException e) {  
  335.             }  
  336.   
  337.         } while (tclazz != Object.class && field == null);  
  338.           
  339.         return (field == null)?null:field.getType().getSimpleName();  
  340.     }  
  341.       
  342.     /** 
  343.      * 将反射时的checked exception转换为unchecked exception. 
  344.      */  
  345.     public static RuntimeException convertReflectionExceptionToUnchecked(Exception e) {  
  346.         if (e instanceof IllegalAccessException || e instanceof IllegalArgumentException  
  347.                 || e instanceof NoSuchMethodException) {  
  348.             return new IllegalArgumentException(e);  
  349.         } else if (e instanceof InvocationTargetException) {  
  350.             return new RuntimeException(((InvocationTargetException) e).getTargetException());  
  351.         } else if (e instanceof RuntimeException) {  
  352.             return (RuntimeException) e;  
  353.         }  
  354.         return new RuntimeException("Unexpected Checked Exception.", e);  
  355.     }  
  356.       
  357.     /** 
  358.      * object 属性名称及属性值组装为String字符串。 
  359.      * 组装规则: 
  360.      * field.name1=field.value1&field.name2=field.value2 ... 
  361.      * @param object 
  362.      * @return 
  363.      */  
  364.     public static String objToString(Object object) {  
  365.         Class<?> clazz = object.getClass();  
  366.         Field[] fss = new Field[0];  
  367.         for (; clazz != Object.class; clazz = clazz.getSuperclass()) {  
  368.             try {  
  369.                 Field[] fs = clazz.getDeclaredFields();  
  370.                 fss = ArrayUtils.addAll(fss, fs);  
  371.             } catch (Exception e) {  
  372.                 // 这里异常不能抛出去。  
  373.                 // 如果这里的异常打印或者往外抛,就不会执行clazz = clazz.getSuperclass(),  
  374.                 // 最后就不会进入到父类中了  
  375.             }  
  376.         }  
  377.         StringBuffer sb = new StringBuffer(50);  
  378.         for (Field f : fss) {  
  379.             // 反射对象中String类型,且不为常量的字段  
  380.             if (String.class.equals(f.getType()) && !isConstant(f.getModifiers())) {  
  381.                 String fieldName = f.getName();  
  382.                 Object o = invokeGetMethod(f.getDeclaringClass(), object, fieldName);  
  383.                 String value = null==o?"":o.toString();  
  384.                 if (value == "") {  
  385.                     continue;  
  386.                 }  
  387.                 sb.append(fieldName + "=" + value + "&");  
  388.             }  
  389.         }  
  390.         logger.info("请求参数:"+sb.toString());  
  391.         return sb.toString();  
  392.     }  
  393.       
  394.     /** 
  395.      * 是否为常量 
  396.      * @param modifiers 
  397.      * @return 常量返回true,非常量返回false 
  398.      */  
  399.     private static boolean isConstant(int modifiers) {  
  400.         // static 和 final修饰  
  401.         if (Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers)) {  
  402.             return true;  
  403.         }   
  404.         return false;  
  405.     }  
  406.       
  407.     /** 
  408.      * 校验参数类型  
  409.      * 目前只校验是否为 常量 
  410.      * @param claszz 
  411.      * @param name 
  412.      * @return 常量返回true,非常量返回false 
  413.      */  
  414.     private static boolean checkModifiers(Class<?> claszz, String name) {  
  415.         try {  
  416.             Field field = claszz.getField(name);  
  417.             if (isConstant(field.getModifiers())) {  
  418.                 return true;  
  419.             }  
  420.         } catch (NoSuchFieldException | SecurityException e) {  
  421.             return false;  
  422.         }   
  423.         return false;  
  424.     }  
  425.       
  426.     /** 
  427.      * 取得属性 
  428.      * @param clazz 
  429.      * @return 
  430.      */  
  431.     public static Map<String, Field> getClassField(Class<?> clazz) {  
  432.         Field[] declaredFields = clazz.getDeclaredFields();  
  433.         Map<String, Field> fieldMap = new HashMap<String, Field>();  
  434.         Map<String, Field> superFieldMap = new HashMap<String, Field>();  
  435.         for (Field field : declaredFields) {  
  436.             fieldMap.put(field.getName(), field);  
  437.         }  
  438.         if (clazz.getSuperclass() != null) {  
  439.             superFieldMap = getClassField(clazz.getSuperclass());  
  440.         }  
  441.         fieldMap.putAll(superFieldMap);  
  442.         return fieldMap;  
  443.     }  
  444.       
  445. }  
Java代码   收藏代码
  1. package com.huatech.common.util;  
  2.   
  3. import org.apache.commons.lang3.StringUtils;  
  4. import org.aspectj.lang.ProceedingJoinPoint;  
  5. import org.aspectj.lang.Signature;  
  6. import org.aspectj.lang.reflect.MethodSignature;  
  7. import org.slf4j.Logger;  
  8. import org.slf4j.LoggerFactory;  
  9. import org.springframework.asm.*;  
  10. import org.springframework.util.CollectionUtils;  
  11.   
  12. import java.io.IOException;  
  13. import java.io.InputStream;  
  14. import java.lang.reflect.Method;  
  15. import java.lang.reflect.Modifier;  
  16. import java.util.ArrayList;  
  17. import java.util.List;  
  18. import java.util.regex.Matcher;  
  19. import java.util.regex.Pattern;  
  20.   
  21. /** 
  22.  * 切面编程工具类 
  23.  * @author lh 
  24.  * @version 3.0 
  25.  * @since 2016-8-26 
  26.  */  
  27. public class AopUtils {  
  28.   
  29.       
  30.     private static final Logger LOGGER = LoggerFactory.getLogger(AopUtils.class);  
  31.     private static final String DESC_DOUBLE = "D";  
  32.     private static final String DESC_SHORT = "J";  
  33.       
  34.     private AopUtils() {    }  
  35.       
  36.     /** 
  37.      * <p>获取方法的参数名</p> 
  38.      * 
  39.      * @param m 
  40.      * @return 
  41.      */  
  42.     public static String[] getMethodParamNames(final Method m) {  
  43.         final String[] paramNames = new String[m.getParameterTypes().length];  
  44.         final String n = m.getDeclaringClass().getName();  
  45.         final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);  
  46.         String className = m.getDeclaringClass().getSimpleName();  
  47.         ClassReader cr = null;  
  48.         InputStream resourceAsStream = null;  
  49.         try {  
  50.             resourceAsStream = Class.forName(n).getResourceAsStream(className + ".class");  
  51.             cr = new ClassReader(resourceAsStream);  
  52.         } catch (IOException | ClassNotFoundException e) {  
  53.             LOGGER.warn(e.getMessage(), e);  
  54.         } finally {  
  55.             if (resourceAsStream != null) {  
  56.                 try {  
  57.                     resourceAsStream.close();  
  58.                 } catch (IOException e) {  
  59.                     LOGGER.warn(e.getMessage(), e);  
  60.                 }  
  61.             }  
  62.         }  
  63.   
  64.         if (cr != null) {  
  65.             cr.accept(new ClassVisitor(Opcodes.ASM4, cw) {  
  66.                 @Override  
  67.                 public MethodVisitor visitMethod(final int access,  
  68.                         final String name, final String desc,  
  69.                         final String signature, final String[] exceptions) {  
  70.                     final Type[] args = Type.getArgumentTypes(desc);  
  71.                     // 方法名相同并且参数个数相同  
  72.                     if (!name.equals(m.getName())  
  73.                             || !sameType(args, m.getParameterTypes())) {  
  74.                         return super.visitMethod(access, name, desc, signature,  
  75.                                 exceptions);  
  76.                     }  
  77.                     MethodVisitor v = cv.visitMethod(access, name, desc, signature,  
  78.                             exceptions);  
  79.                     return new MethodVisitor(Opcodes.ASM4, v) {  
  80.                           
  81.                         int fixCount = 0;//步长修正计数器  
  82.                           
  83.                         @Override  
  84.                         public void visitLocalVariable(String name, String desc,  
  85.                                 String signature, Label start, Label end, int index) {  
  86.                             int i = index - 1;  
  87.                             // 如果是静态方法,则第一就是参数  
  88.                             // 如果不是静态方法,则第一个是"this",然后才是方法的参数  
  89.                             if (Modifier.isStatic(m.getModifiers())) {  
  90.                                 i = index;  
  91.                             }  
  92.                             if (i > fixCount) {  
  93.                                 i -= fixCount;  
  94.                             }  
  95.                             if(desc.equals(DESC_SHORT) || desc.equals(DESC_DOUBLE)){  
  96.                                 fixCount++;  
  97.                             }  
  98.                             if (i >= 0 && i < paramNames.length) {  
  99.                                 paramNames[i] = name;  
  100.                             }  
  101.                             super.visitLocalVariable(name, desc, signature, start,  
  102.                                     end, index);  
  103.                         }  
  104.                           
  105.                     };  
  106.                 }  
  107.             }, 0);            
  108.         }  
  109.         return paramNames;  
  110.     }  
  111.   
  112.     /** 
  113.      * <p>比较参数类型是否一致</p> 
  114.      * 
  115.      * @param types   asm的类型({@link Type}) 
  116.      * @param clazzes java 类型({@link Class}) 
  117.      * @return 
  118.      */  
  119.     private static boolean sameType(Type[] types, Class<?>[] clazzes) {  
  120.         // 个数不同  
  121.         if (types.length != clazzes.length) {  
  122.             return false;  
  123.         }  
  124.   
  125.         for (int i = 0; i < types.length; i++) {  
  126.             if (!Type.getType(clazzes[i]).equals(types[i])) {  
  127.                 return false;  
  128.             }  
  129.         }  
  130.         return true;  
  131.     }  
  132.       
  133.     /** 
  134.      * 取得切面调用的方法 
  135.      * @param pjp 
  136.      * @return 
  137.      */  
  138.     public static Method getMethod(ProceedingJoinPoint pjp){  
  139.         Signature sig = pjp.getSignature();  
  140.         if (!(sig instanceof MethodSignature)) {  
  141.             throw new IllegalArgumentException("该注解只能用于方法");  
  142.         }  
  143.         MethodSignature msig = (MethodSignature) sig;  
  144.         Object target = pjp.getTarget();  
  145.         Method currentMethod = null;  
  146.         try {  
  147.             currentMethod = target.getClass().getMethod(msig.getName(), msig.getParameterTypes());  
  148.         } catch (NoSuchMethodException | SecurityException e) {  
  149.             LOGGER.warn(e.getMessage(), e);  
  150.         }         
  151.         return currentMethod;  
  152.     }  
  153.       
  154.     public static List<String> getMatcher(String regex, String source) {    
  155.         List<String> list = new ArrayList<>();  
  156.         Pattern pattern = Pattern.compile(regex);    
  157.         Matcher matcher = pattern.matcher(source);    
  158.         while (matcher.find()) {    
  159.             list.add(matcher.group());  
  160.         }    
  161.         return list;    
  162.     }  
  163.       
  164.     /** 
  165.      * 取得注解参数 
  166.         (?=exp) 匹配exp前面的位置 
  167.         (?<=exp) 匹配exp后面的位置 
  168.         (?!exp) 匹配后面跟的不是exp的位置 
  169.         (?<!exp) 匹配前面不是exp的位置 
  170.      * @param managers 
  171.      * @return 
  172.      */  
  173.     public static List<String> getAnnoParams(String source){  
  174.         String regex = "(?<=\\{)(.+?)(?=\\})";  
  175.         return getMatcher(regex, source);  
  176.     }  
  177.       
  178.     /** 
  179.      * 获取缓存的key值 
  180.      *  
  181.      * @param pjp 
  182.      * @param key 
  183.      * @return 
  184.      */  
  185.     public static String getCacheKey(final ProceedingJoinPoint pjp, final String key) {  
  186.   
  187.         StringBuilder buf = new StringBuilder();  
  188.         final Object[] args = pjp.getArgs();  
  189.           
  190.         if(StringUtils.isNotBlank(key)){  
  191.             buf.append(key);  
  192.             List<String> annoParamNames = AopUtils.getAnnoParams(key);  
  193.             String[] methodParamNames = AopUtils.getMethodParamNames(AopUtils.getMethod(pjp));  
  194.             if(!CollectionUtils.isEmpty(annoParamNames)){  
  195.                 for (String ap : annoParamNames) {  
  196.                     buf = replaceParam(buf, args, methodParamNames, ap);  
  197.                 }                 
  198.             }  
  199.               
  200.         }else{  
  201.             buf.append(pjp.getSignature().getDeclaringTypeName()).append(":").append(pjp.getSignature().getName());  
  202.             for (Object arg : args) {  
  203.                 buf.append(":").append(arg.toString());  
  204.             }  
  205.         }     
  206.   
  207.         return buf.toString();  
  208.     }  
  209.   
  210.     /** 
  211.      * 替换占位参数 
  212.      * @param buf 
  213.      * @param args 
  214.      * @param methodParamNames 
  215.      * @param ap 
  216.      * @return 
  217.      */  
  218.     private static StringBuilder replaceParam(StringBuilder buf, final Object[] args, String[] methodParamNames, String ap) {  
  219.         StringBuilder builder = new StringBuilder(buf);  
  220.         String paramValue = "";  
  221.         for (int i = 0; i < methodParamNames.length; i++) {  
  222.             if(ap.startsWith(methodParamNames[i])){  
  223.                 final Object arg = args[i];  
  224.                 if (ap.contains(".")) {  
  225.                     paramValue = String.valueOf(ReflectionUtils.invokeGetter(arg, ap.substring(ap.indexOf('.') + 1)));  
  226.                 } else {  
  227.                     paramValue = String.valueOf(arg);  
  228.                 }  
  229.                 break;  
  230.             }  
  231.         }  
  232.         int start = builder.indexOf("{" + ap);  
  233.         int end = start + ap.length() + 2;  
  234.         builder =builder.replace(start, end, paramValue);  
  235.         return builder;  
  236.     }  
  237.       
  238. }  
Java代码   收藏代码
  1. package com.huatech.common.util;  
  2.   
  3. public class StringUtil {  
  4.       
  5.   
  6.     /** 
  7.      * 首字母大写 
  8.      *  
  9.      * @param s 
  10.      * @return 
  11.      */  
  12.     public static String firstCharUpperCase(String s) {  
  13.         StringBuffer sb = new StringBuffer(s.substring(0, 1).toUpperCase());  
  14.         sb.append(s.substring(1, s.length()));  
  15.         return sb.toString();  
  16.     }  
  17.   
  18. }  
Java代码   收藏代码
  1. package com.huatech.common.util;  
  2.   
  3. import java.util.List;  
  4. import java.util.Map;  
  5. import java.util.Set;  
  6. import java.util.concurrent.TimeUnit;  
  7.   
  8. import org.apache.commons.lang3.StringUtils;  
  9. import org.slf4j.Logger;  
  10. import org.slf4j.LoggerFactory;  
  11. import org.springframework.data.redis.core.BoundHashOperations;  
  12. import org.springframework.data.redis.core.RedisTemplate;  
  13. import org.springframework.data.redis.core.StringRedisTemplate;  
  14.   
  15. import com.alibaba.fastjson.JSON;  
  16. import com.alibaba.fastjson.JSONObject;  
  17. import com.huatech.common.support.SpringContextHolder;  
  18.   
  19. /** 
  20.  * 通用缓存工具类 
  21.  * @author lh 
  22.  * @version 3.0 
  23.  * @since 2016-6-22 
  24.  * 
  25.  */  
  26. public class CacheUtils {  
  27.   
  28.     private static final Logger LOGGER = LoggerFactory.getLogger(CacheUtils.class);  
  29.       
  30.     public static RedisTemplate<String, Object> redisTemplate = SpringContextHolder.getBean("redisTemplate");  
  31.     public static StringRedisTemplate stringRedisTemplate = SpringContextHolder.getBean("stringRedisTemplate");  
  32.   
  33.     private static String redisKeyPrefix = PropertiesUtil.getValueByKey(CacheUtils.class.getResource("/").getPath() + "config/redis.properties", "redis.keyPrefix");  
  34.       
  35.     private CacheUtils() {  
  36.     }  
  37.       
  38.     /** 
  39.      * 删除缓存<br> 
  40.      * 根据key精确匹配删除 
  41.      *  
  42.      * @param key 
  43.      */  
  44.     public static void del(String... key) {  
  45.         LOGGER.warn("delete cache, keys in ({})", merge(key));  
  46.         for (String k : key) {  
  47.             redisTemplate.delete(appendKeyPrefix(k));  
  48.         }  
  49.     }  
  50.   
  51.     /** 
  52.      * 批量删除<br> 
  53.      * (该操作会执行模糊查询,请尽量不要使用,以免影响性能或误删) 
  54.      *  
  55.      * @param pattern 
  56.      */  
  57.     public static void batchDel(String... pattern) {  
  58.         LOGGER.warn("batchDel cache, pattern in ({})", merge(pattern));  
  59.         for (String kp : pattern) {  
  60.             redisTemplate.delete(redisTemplate.keys(appendKeyPrefix(kp) + "*"));  
  61.         }  
  62.     }  
  63.   
  64.     /** 
  65.      * 取得缓存(int型) 
  66.      *  
  67.      * @param key 
  68.      * @return 
  69.      */  
  70.     public static Integer getInt(String key) {  
  71.         String value = stringRedisTemplate.boundValueOps(appendKeyPrefix(key)).get();  
  72.         if (StringUtils.isNotBlank(value)) {  
  73.             return Integer.valueOf(value);  
  74.         }  
  75.         return 0;  
  76.     }  
  77.       
  78.     /** 
  79.      * 取得缓存(long型) 
  80.      *  
  81.      * @param key 
  82.      * @return 
  83.      */  
  84.     public static Long getLong(String key) {  
  85.         String value = stringRedisTemplate.boundValueOps(appendKeyPrefix(key)).get();  
  86.         if (StringUtils.isNotBlank(value)) {  
  87.             return Long.valueOf(value);  
  88.         }  
  89.         return 0l;  
  90.     }  
  91.   
  92.     /** 
  93.      * 取得缓存(字符串类型) 
  94.      *  
  95.      * @param key 
  96.      * @return 
  97.      */  
  98.     public static String getStr(String key) {  
  99.         return stringRedisTemplate.boundValueOps(appendKeyPrefix(key)).get();  
  100.     }  
  101.   
  102.     /** 
  103.      * 取得缓存(字符串类型) 
  104.      *  
  105.      * @param key 
  106.      * @return 
  107.      */  
  108.     public static String getStr(String key, boolean retain) {  
  109.         String value = stringRedisTemplate.boundValueOps(appendKeyPrefix(key)).get();  
  110.         if (!retain) {  
  111.             stringRedisTemplate.delete(appendKeyPrefix(key));  
  112.         }  
  113.         return value;  
  114.     }  
  115.   
  116.     /** 
  117.      * 获取缓存<br> 
  118.      * 注:基本数据类型(Character除外),请直接使用get(String key, Class<T> clazz)取值 
  119.      *  
  120.      * @param key 
  121.      * @return 
  122.      */  
  123.     public static Object getObj(String key) {  
  124.         return redisTemplate.boundValueOps(appendKeyPrefix(key)).get();  
  125.     }  
  126.   
  127.     /** 
  128.      * 获取缓存<br> 
  129.      * 注:java 8种基本类型的数据请直接使用get(String key, Class<T> clazz)取值 
  130.      *  
  131.      * @param key 
  132.      * @param retain 
  133.      *            是否保留 
  134.      * @return 
  135.      */  
  136.     public static Object getObj(String key, boolean retain) {  
  137.         Object obj = redisTemplate.boundValueOps(appendKeyPrefix(key)).get();  
  138.         if (!retain && obj != null) {  
  139.             redisTemplate.delete(appendKeyPrefix(key));  
  140.         }  
  141.         return obj;  
  142.     }  
  143.   
  144.     /** 
  145.      * 获取缓存<br> 
  146.      * 注:慎用java基本数据类型进行转换(可能会出现空值,转换报错) 
  147.      *  
  148.      * @param key 
  149.      *            key 
  150.      * @param clazz 
  151.      *            类型 
  152.      * @return 
  153.      */  
  154.     @SuppressWarnings("unchecked")  
  155.     public static <T> T get(String key, Class<T> clazz) {  
  156.         key = appendKeyPrefix(key);  
  157.         if (clazz.equals(String.class)) {  
  158.             return (T) stringRedisTemplate.boundValueOps(key).get();  
  159.         } else if (clazz.equals(Integer.class) || clazz.equals(Long.class)) {  
  160.             return (T) stringRedisTemplate.boundValueOps(key).get();  
  161.         } else if (clazz.equals(Double.class) || clazz.equals(Float.class)) {  
  162.             return (T) stringRedisTemplate.boundValueOps(key).get();  
  163.         } else if (clazz.equals(Short.class) || clazz.equals(Boolean.class)) {  
  164.             return (T) stringRedisTemplate.boundValueOps(key).get();  
  165.         }  
  166.         return (T) redisTemplate.boundValueOps(key).get();  
  167.     }  
  168.   
  169.       
  170.     /** 
  171.      * 将value对象写入缓存 
  172.      *  
  173.      * @param key 
  174.      * @param value 
  175.      * @param seconds 
  176.      *            失效时间(秒) 
  177.      */  
  178.     public static void set(String key, Object value, long seconds) {  
  179.         if (null == key || null == value) {  
  180.             throw new RuntimeException("key or value must not null");  
  181.         }  
  182.         key = appendKeyPrefix(key);  
  183.         if (value instanceof String) {  
  184.             stringRedisTemplate.opsForValue().set(key, value.toString());  
  185.         } else if (value instanceof Integer || value instanceof Long) {  
  186.             stringRedisTemplate.opsForValue().set(key, value.toString());  
  187.         } else if (value instanceof Double || value instanceof Float) {  
  188.             stringRedisTemplate.opsForValue().set(key, value.toString());  
  189.         } else if (value instanceof Short || value instanceof Boolean) {  
  190.             stringRedisTemplate.opsForValue().set(key, value.toString());  
  191.         } else {  
  192.             redisTemplate.opsForValue().set(key, value);  
  193.         }  
  194.         if (seconds > 0) {  
  195.             redisTemplate.expire(key, seconds, TimeUnit.SECONDS);  
  196.         }  
  197.     }  
  198.   
  199.   
  200.     /** 
  201.      * 更新key对象field的值 
  202.      *  
  203.      * @param key 
  204.      *            缓存key 
  205.      * @param field 
  206.      *            缓存对象field 
  207.      * @param value 
  208.      *            缓存对象field值 
  209.      */  
  210.     public static void setJsonField(String key, String field, String value) {  
  211.         JSONObject obj = JSON.parseObject(stringRedisTemplate.boundValueOps(appendKeyPrefix(key)).get());  
  212.         obj.put(field, value);  
  213.         stringRedisTemplate.opsForValue().set(appendKeyPrefix(key), obj.toJSONString());  
  214.     }  
  215.   
  216.     /** 
  217.      * 递减操作 
  218.      *  
  219.      * @param key 
  220.      * @param by 
  221.      * @return 
  222.      */  
  223.     public static double decr(String key, double by) {  
  224.         return redisTemplate.opsForValue().increment(appendKeyPrefix(key), -by);  
  225.     }  
  226.   
  227.     /** 
  228.      * 递增操作 
  229.      *  
  230.      * @param key 
  231.      * @param by 
  232.      * @return 
  233.      */  
  234.     public static double incr(String key, double by) {  
  235.         return redisTemplate.opsForValue().increment(appendKeyPrefix(key), by);  
  236.     }  
  237.   
  238.     /** 
  239.      * 递减操作 
  240.      *  
  241.      * @param key 
  242.      * @param by 
  243.      * @return 
  244.      */  
  245.     public static long decr(String key, long by) {  
  246.         return redisTemplate.opsForValue().increment(appendKeyPrefix(key), -by);  
  247.     }  
  248.   
  249.     /** 
  250.      * 递增操作 
  251.      *  
  252.      * @param key 
  253.      * @param by 
  254.      * @return 
  255.      */  
  256.     public static long incr(String key, long by) {  
  257.         return redisTemplate.opsForValue().increment(appendKeyPrefix(key), by);  
  258.     }  
  259.   
  260.     /** 
  261.      * 获取double类型值 
  262.      *  
  263.      * @param key 
  264.      * @return 
  265.      */  
  266.     public static double getDouble(String key) {  
  267.         String value = stringRedisTemplate.boundValueOps(appendKeyPrefix(key)).get();  
  268.         if (StringUtils.isNotBlank(value)) {  
  269.             return Double.valueOf(value);  
  270.         }  
  271.         return 0d;  
  272.     }  
  273.   
  274.     /** 
  275.      * 设置double类型值 
  276.      *  
  277.      * @param key 
  278.      * @param value 
  279.      * @param seconds 
  280.      *            失效时间(秒) 
  281.      */  
  282.     public static void setDouble(String key, double value, long seconds) {  
  283.         stringRedisTemplate.opsForValue().set(appendKeyPrefix(key), String.valueOf(value));  
  284.         if (seconds > 0) {  
  285.             stringRedisTemplate.expire(appendKeyPrefix(key), seconds, TimeUnit.SECONDS);  
  286.         }  
  287.     }  
  288.   
  289.     /** 
  290.      * 将map写入缓存 
  291.      *  
  292.      * @param key 
  293.      * @param map 
  294.      */  
  295.     public static <T> void setMap(String key, Map<String, T> map) {  
  296.         redisTemplate.opsForHash().putAll(appendKeyPrefix(key), map);  
  297.     }  
  298.   
  299.   
  300.     /** 
  301.      * 向key对应的map中添加缓存对象 
  302.      *  
  303.      * @param key 
  304.      * @param map 
  305.      */  
  306.     public static <T> void addMap(String key, Map<String, T> map) {  
  307.         redisTemplate.opsForHash().putAll(appendKeyPrefix(key), map);  
  308.     }  
  309.   
  310.     /** 
  311.      * 向key对应的map中添加缓存对象 
  312.      *  
  313.      * @param key 
  314.      *            cache对象key 
  315.      * @param field 
  316.      *            map对应的key 
  317.      * @param value 
  318.      *            值 
  319.      */  
  320.     public static void addMap(String key, String field, String value) {  
  321.         redisTemplate.opsForHash().put(appendKeyPrefix(key), field, value);  
  322.     }  
  323.   
  324.     /** 
  325.      * 向key对应的map中添加缓存对象 
  326.      *  
  327.      * @param key 
  328.      *            cache对象key 
  329.      * @param field 
  330.      *            map对应的key 
  331.      * @param obj 
  332.      *            对象 
  333.      */  
  334.     public static <T> void addMap(String key, String field, T obj) {  
  335.         redisTemplate.opsForHash().put(appendKeyPrefix(key), field, obj);  
  336.     }  
  337.   
  338.     /** 
  339.      * 获取map缓存 
  340.      *  
  341.      * @param key 
  342.      * @param clazz 
  343.      * @return 
  344.      */  
  345.     public static <T> Map<String, T> mget(String key, Class<T> clazz) {  
  346.         BoundHashOperations<String, String, T> boundHashOperations = redisTemplate.boundHashOps(appendKeyPrefix(key));      
  347.         return boundHashOperations.entries();  
  348.     }  
  349.   
  350.     /** 
  351.      * 获取map缓存中的某个对象 
  352.      *  
  353.      * @param key 
  354.      * @param field 
  355.      * @param clazz 
  356.      * @return 
  357.      */  
  358.     @SuppressWarnings("unchecked")  
  359.     public static <T> T getMapField(String key, String field, Class<T> clazz) {  
  360.         return (T) redisTemplate.boundHashOps(appendKeyPrefix(key)).get(field);  
  361.     }  
  362.   
  363.     /** 
  364.      * 删除map中的某个对象 
  365.      *  
  366.      * @author lh 
  367.      * @date 2016年8月10日 
  368.      * @param key 
  369.      *            map对应的key 
  370.      * @param field 
  371.      *            map中该对象的key 
  372.      */  
  373.     public static void delMapField(String key, String... field) {  
  374.         redisTemplate.opsForHash().delete(appendKeyPrefix(key), field);  
  375.     }  
  376.   
  377.     /** 
  378.      * 为哈希表key中的域field的值 
  379.      *  
  380.      * @param key 
  381.      *            键 
  382.      * @param field 
  383.      *            map域 
  384.      * @param value 
  385.      *            增量值 
  386.      * @return 
  387.      */  
  388.     public static long hincr(String key, String field, long value) {  
  389.         return redisTemplate.opsForHash().increment(appendKeyPrefix(key), field, value);  
  390.     }  
  391.       
  392.     public static void hset(String key, String field, Object value){  
  393.         redisTemplate.opsForHash().put(appendKeyPrefix(key), field, value);  
  394.     }  
  395.       
  396.     public static Object hget(String key, String field){  
  397.         return redisTemplate.boundHashOps(appendKeyPrefix(key)).get(field);  
  398.     }  
  399.       
  400.     public static void hdel(String key, String...fields){  
  401.         if (fields == null || fields.length == 0) {  
  402.             redisTemplate.delete(appendKeyPrefix(key));  
  403.         }else{  
  404.             redisTemplate.opsForHash().delete(appendKeyPrefix(key), fields);              
  405.         }  
  406.     }  
  407.       
  408.     public static Long hlen(String key){  
  409.         return redisTemplate.boundHashOps(appendKeyPrefix(key)).size();  
  410.     }  
  411.     public static <T> Set<T> hkeys(String key){  
  412.         return (Set<T>)redisTemplate.boundHashOps(appendKeyPrefix(key)).keys();  
  413.     }  
  414.     public static <T> List<T> hvals(String key){  
  415.         return (List<T>)redisTemplate.boundHashOps(appendKeyPrefix(key)).values();  
  416.     }  
  417.   
  418.     /** 
  419.      *  
  420.      * @param key 
  421.      * @param value 
  422.      * @param seconds 
  423.      * @return 
  424.      */  
  425.     public static boolean setnx(String key, String value, long seconds) {  
  426.         boolean flag = stringRedisTemplate.opsForValue().setIfAbsent(appendKeyPrefix(key), value);  
  427.         if (seconds > 0) {  
  428.             redisTemplate.expire(appendKeyPrefix(key), seconds, TimeUnit.SECONDS);  
  429.         }  
  430.         return flag;  
  431.     }  
  432.   
  433.     /** 
  434.      * 指定缓存的失效时间 
  435.      *  
  436.      * @author FangJun 
  437.      * @date 2016年8月14日 
  438.      * @param key 
  439.      *            缓存KEY 
  440.      * @param seconds 
  441.      *            失效时间(秒) 
  442.      */  
  443.     public static void expire(String key, long seconds) {  
  444.         redisTemplate.expire(appendKeyPrefix(key), seconds, TimeUnit.SECONDS);  
  445.     }  
  446.   
  447.     /** 
  448.      * 指定缓存的失效时间 
  449.      *  
  450.      * @author FangJun 
  451.      * @date 2016年8月14日 
  452.      * @param key 
  453.      *            缓存KEY 
  454.      * @param seconds 
  455.      *            失效时间(秒) 
  456.      */  
  457.     public static void expire(String key, int seconds) {  
  458.         redisTemplate.expire(appendKeyPrefix(key), seconds, TimeUnit.SECONDS);  
  459.     }  
  460.   
  461.     /** 
  462.      * 添加set 
  463.      *  
  464.      * @param key 
  465.      * @param value 
  466.      */  
  467.     public static void sadd(String key, String... value) {  
  468.         redisTemplate.boundSetOps(appendKeyPrefix(key)).add(value);  
  469.     }  
  470.   
  471.     /** 
  472.      * 删除set集合中的对象 
  473.      *  
  474.      * @param key 
  475.      * @param value 
  476.      */  
  477.     public static void srem(String key, String... value) {  
  478.         redisTemplate.boundSetOps(appendKeyPrefix(key)).remove(value);  
  479.     }  
  480.   
  481.   
  482.     /** 
  483.      * 判断key对应的缓存是否存在 
  484.      *  
  485.      * @param key 
  486.      * @return 
  487.      */  
  488.     public static boolean exists(String key) {  
  489.         return redisTemplate.hasKey(appendKeyPrefix(key));  
  490.     }  
  491.       
  492.      /**  
  493.      * 模糊查询keys  
  494.      * @param pattern  
  495.      * @return  
  496.      */    
  497.     public static Set<String> keys(String pattern){    
  498.         return redisTemplate.keys(appendKeyPrefix(pattern));     
  499.     }    
  500.   
  501.     /** 
  502.      * 合并数组为字符串 
  503.      * @param strings 
  504.      * @return 
  505.      */  
  506.     private static String merge(String...strings){  
  507.         if (strings == null || strings.length == 0) {  
  508.             return null;  
  509.         }  
  510.         StringBuffer sb = new StringBuffer();  
  511.         int len = strings.length;  
  512.         for (int i = 0; i < len; i++) {  
  513.             sb.append(strings[i]);  
  514.             if(len != i+1){  
  515.                 sb.append(",");  
  516.             }  
  517.         }  
  518.         return sb.toString();  
  519.     }  
  520.       
  521.     private static String appendKeyPrefix(String key){  
  522.         return redisKeyPrefix.concat(key);  
  523.     }  
  524.       
  525. }  
扫描二维码关注公众号,回复: 2112112 查看本文章

4、增加AOP支持

Java代码   收藏代码
  1. package com.huatech.support.redis;  
  2.   
  3. import java.util.Set;  
  4. import java.util.concurrent.TimeUnit;  
  5.   
  6. import org.aspectj.lang.ProceedingJoinPoint;  
  7. import org.aspectj.lang.annotation.Around;  
  8. import org.aspectj.lang.annotation.Aspect;  
  9. import org.slf4j.Logger;  
  10. import org.slf4j.LoggerFactory;  
  11. import org.springframework.beans.factory.annotation.Autowired;  
  12. import org.springframework.beans.factory.annotation.Value;  
  13. import org.springframework.data.redis.core.RedisTemplate;  
  14. import org.springframework.data.redis.core.ValueOperations;  
  15. import org.springframework.stereotype.Component;  
  16. import org.springframework.util.CollectionUtils;  
  17.   
  18. import com.huatech.common.annotation.CacheEvict;  
  19. import com.huatech.common.annotation.Cacheable;  
  20. import com.huatech.common.util.AopUtils;  
  21. import com.huatech.common.util.CacheUtils;  
  22. /** 
  23.  * 缓存操作切面 
  24.  * 注意:一个支持缓存的方法,在对象内部被调用是不会触发缓存功能的。 
  25.  * @author lh 
  26.  * 
  27.  */  
  28. @Aspect  
  29. @Component  
  30. public class CacheAspect {  
  31.       
  32.     /** 
  33.      * 缓存清除标识前缀 
  34.      */  
  35.     public static final String  KEY_PREFIX_CACHE_EVICT="cacheEvict:interval:";  
  36.       
  37.     public static final String REDIS_CACHE_SUPPORT = "1";  
  38.       
  39.     private static final Logger LOGGER = LoggerFactory.getLogger(CacheAspect.class);  
  40.       
  41.       
  42.     @SuppressWarnings("rawtypes")  
  43.     @Autowired  
  44.     private RedisTemplate redisTemplate;  
  45.   
  46.     @Value("${redis.cacheSupport}")  
  47.     private String redisCacheSupport;  
  48.       
  49.     @Value("${redis.keyPrefix}")  
  50.     private String redisKeyPrefix;  
  51.       
  52.       
  53.     /** 
  54.      * 启用新的get方法,防止缓存被“击穿” 
  55.      * <p> 
  56.      * 击穿 :缓存在某个时间点过期的时候,恰好在这个时间点对这个Key有大量的并发请求过来, 
  57.      *      这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮。 
  58.      * 如何解决:业界比较常用的做法,是使用mutex。 
  59.      *      简单地来说,就是在缓存失效的时候(判断拿出来的值为空),不是立即去load db,而是先使用缓存工具的某些带成 
  60.      *      功操作返回值的操作(比如Redis的SETNX或者Memcache的ADD)去set一个mutex key,当操作返回成功时,再进行 
  61.      *      load db的操作并回设缓存;否则,就重试整个get缓存的方法。 
  62.      * </p> 
  63.      * @param key 
  64.      * @param pjp 
  65.      * @param cache 
  66.      * @return 
  67.      * @throws Throwable 
  68.      */  
  69.     private Object get(final String key, final ProceedingJoinPoint pjp, final Cacheable cache) throws Throwable {  
  70.         @SuppressWarnings("unchecked")  
  71.         ValueOperations<String, Object> valueOper = redisTemplate.opsForValue();  
  72.         Object value = valueOper.get(key); // 从缓存获取数据  
  73.         if (value == null) { // 代表缓存值过期  
  74.             // 设置2min的超时,防止del操作失败的时候,下次缓存过期一直不能load db  
  75.             String keynx = key.concat(":nx");  
  76.             if (CacheUtils.setnx(keynx, "1", 5)) { // 代表设置成功  
  77.                 value = pjp.proceed();  
  78.                 if (cache.expire() <= 0) { // 如果没有设置过期时间,则无限期缓存  
  79.                     valueOper.set(key, value);  
  80.                 } else { // 否则设置缓存时间  
  81.                     valueOper.set(key, value, cache.expire(), TimeUnit.SECONDS);  
  82.                 }  
  83.                 CacheUtils.del(keynx);  
  84.                 return value;  
  85.             } else { // 这个时候代表同时候的其他线程已经load db并回设到缓存了,这时候重试获取缓存值即可  
  86.                 Thread.sleep(10);  
  87.                 return get(key, pjp, cache); // 重试  
  88.             }  
  89.         } else {  
  90.             return value;  
  91.         }  
  92.     }  
  93.     /** 
  94.      * 添加缓存 
  95.      * @param pjp 
  96.      * @param cache 
  97.      * @return 
  98.      * @throws Throwable 
  99.      */  
  100.     @Around("@annotation(cache)")  
  101.     public Object cacheable(final ProceedingJoinPoint pjp, Cacheable cache)throws Throwable {  
  102.         if(REDIS_CACHE_SUPPORT.equals(redisCacheSupport)){  
  103.             String key = redisKeyPrefix.concat(AopUtils.getCacheKey(pjp, cache.key()));  
  104.             return get(key, pjp, cache);              
  105.         }  
  106.         return pjp.proceed();  
  107.     }  
  108.       
  109.       
  110.     @Around("@annotation(evict)")  
  111.     public Object cacheEvict(final ProceedingJoinPoint pjp, CacheEvict evict)throws Throwable {  
  112.         if(REDIS_CACHE_SUPPORT.equals(redisCacheSupport)){  
  113.             Object value = pjp.proceed();  
  114.             //清除keys对应的缓存数据  
  115.             if (evict.keys() != null && evict.keys().length > 0) {  
  116.                 for (String keyname : evict.keys()) {  
  117.                     evictByKeyname(pjp, keyname,evict.interval());  
  118.                 }  
  119.             }  
  120.             return value;             
  121.         }  
  122.         return pjp.proceed();  
  123.     }  
  124.   
  125.     @SuppressWarnings("unchecked")  
  126.     private void evictByKeyname(final ProceedingJoinPoint pjp, final String keyname, long interval) {  
  127.         final String key = redisKeyPrefix.concat(AopUtils.getCacheKey(pjp, keyname));  
  128.         //操作间隔判断  
  129.         if (interval != 0) {  
  130.             final String intervalKey = KEY_PREFIX_CACHE_EVICT + key;  
  131.             if (CacheUtils.incr(intervalKey, 1) > 1) {  
  132.                 return;  
  133.             }  
  134.             CacheUtils.expire(intervalKey, interval);  
  135.         }  
  136.           
  137.         LOGGER.info("cacheEvict, key={}", key);           
  138.           
  139.         //使用redisTemplate操作缓存  
  140.         if (keyname.equals(key)) {// 支持批量删除  
  141.             Set<String> keys = redisTemplate.keys(key.concat("*"));  
  142.             if (!CollectionUtils.isEmpty(keys)) {  
  143.                 redisTemplate.delete(keys);  
  144.             }  
  145.         } else {  
  146.             redisTemplate.delete(key);  
  147.         }  
  148.     }  
  149.   
  150.       
  151. }  

5、扩展spring-data-redis,简化配置

Java代码   收藏代码
  1. package com.huatech.support.redis;  
  2.   
  3. import static org.springframework.util.Assert.isTrue;  
  4. import static org.springframework.util.Assert.notNull;  
  5. import static org.springframework.util.StringUtils.split;  
  6.   
  7. import org.apache.commons.lang3.StringUtils;  
  8. import org.springframework.data.redis.connection.RedisClusterConfiguration;  
  9. import org.springframework.data.redis.connection.RedisNode;  
  10. /** 
  11.  * <p>RedisCluster配置</p> 
  12.  * <p>用于简化spring-data-redis配置</p> 
  13.  * @author lh 
  14.  * @version 3.0 
  15.  * @since 2017-4-5 
  16.  * 
  17.  */  
  18. public class RedisClusterConfig extends RedisClusterConfiguration{  
  19.   
  20.     public RedisClusterConfig(String nodes, Integer maxRedirects) {  
  21.         super();  
  22.         initNodes(nodes);  
  23.         setMaxRedirects(maxRedirects);  
  24.     }  
  25.       
  26.     private void initNodes(String nodes){  
  27.         if(StringUtils.isBlank(nodes)){  
  28.             throw new RuntimeException("nodes can not be empty!");  
  29.         }  
  30.         String[] hostAndPorts = nodes.split(",");  
  31.         for (String hostAndPort : hostAndPorts) {  
  32.             addClusterNode(readHostAndPortFromString(hostAndPort));  
  33.         }  
  34.     }  
  35.       
  36.     private RedisNode readHostAndPortFromString(String hostAndPort) {  
  37.         String[] args = split(hostAndPort, ":");  
  38.         notNull(args, "HostAndPort need to be seperated by  ':'.");  
  39.         isTrue(args.length == 2, "Host and Port String needs to specified as host:port");  
  40.         return new RedisNode(args[0], Integer.valueOf(args[1]).intValue());  
  41.     }  
  42.       
  43. }  
Java代码   收藏代码
  1. package com.huatech.support.redis;  
  2.   
  3. import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;  
  4. /** 
  5.  * Jedis Single Connection factory  
  6.  * @author lh 
  7.  * 
  8.  */  
  9. public class RedisSingleConnFactory extends JedisConnectionFactory {  
  10.       
  11.     public RedisSingleConnFactory(String address,int timeout, String password, redis.clients.jedis.JedisPoolConfig poolConfig) {  
  12.         String[] hostAndPorts = address.split(":");  
  13.         setHostName(hostAndPorts[0]);  
  14.         setPort(Integer.valueOf(hostAndPorts[1]));  
  15.         setTimeout(timeout);  
  16.         setPassword(password);  
  17.         setPoolConfig(poolConfig);  
  18.     }  
  19.       
  20.     public RedisSingleConnFactory(String address, String password, redis.clients.jedis.JedisPoolConfig poolConfig) {  
  21.         String[] hostAndPorts = address.split(":");  
  22.         setHostName(hostAndPorts[0]);  
  23.         setPort(Integer.valueOf(hostAndPorts[1]));  
  24.         setPassword(password);  
  25.         setPoolConfig(poolConfig);  
  26.     }  
  27.       
  28.     public RedisSingleConnFactory(String address, redis.clients.jedis.JedisPoolConfig poolConfig) {  
  29.         String[] hostAndPorts = address.split(":");  
  30.         setHostName(hostAndPorts[0]);  
  31.         setPort(Integer.valueOf(hostAndPorts[1]));  
  32.         setPoolConfig(poolConfig);  
  33.     }  
  34. }  

6、添加redis配置文件:redis.properties

Properties代码   收藏代码
  1. #redis settings  
  2. redis.cacheSupport=1  
  3. redis.keyPrefix=bds_  
  4.   
  5. #redis pool settings  
  6. redis.pool.maxTotal=60000  
  7. redis.pool.maxIdle=300  
  8. redis.pool.testOnBorrow=true  
  9.   
  10. #redis 单机配置  
  11. spring.redis.single.node=172.16.90.30:6379  
  12. spring.redis.single.timeout=8000  
  13. spring.redis.single.password=redis  
  14.   
  15. #redis 集群  
  16. spring.redis.cluster.maxRedirects=3  
  17. spring.redis.cluster.nodes=192.168.42.128:6379,192.168.42.128:6380,192.168.42.129:6379,192.168.42.129:6380,192.168.42.130:6379,192.168.42.130:6380  

7、在applicationContext.xml文件中添加redis配置

Xml代码   收藏代码
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"   
  3.     xmlns:p="http://www.springframework.org/schema/p"  
  4.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  5.     xmlns:context="http://www.springframework.org/schema/context"   
  6.     xmlns:aop="http://www.springframework.org/schema/aop"   
  7.     xsi:schemaLocation="  
  8.         http://www.springframework.org/schema/beans   
  9.         http://www.springframework.org/schema/beans/spring-beans-4.0.xsd  
  10.         http://www.springframework.org/schema/context    
  11.         http://www.springframework.org/schema/context/spring-context-4.0.xsd  
  12.         http://www.springframework.org/schema/aop   
  13.         http://www.springframework.org/schema/aop/spring-aop-4.0.xsd" >  
  14.   
  15.     <description>Redis Configuration</description>  
  16.           
  17.     <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">  
  18.         <property name="order" value="1" />  
  19.         <property name="ignoreUnresolvablePlaceholders" value="true" />  
  20.         <property name="locations">  
  21.             <list>  
  22.                 <value>classpath:/mybatis/jdbc.properties</value>  
  23.                 <value>classpath:/config/redis.properties</value>  
  24.             </list>  
  25.         </property>  
  26.     </bean>  
  27.       
  28.     <aop:aspectj-autoproxy/>    
  29.       
  30.     <context:component-scan base-package="com.huatech.support"/>  
  31.       
  32.     <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">  
  33.         <property name="maxIdle" value="${redis.pool.maxIdle}" /> <!-- 最大能够保持idel状态的对象数  -->  
  34.         <property name="maxTotal" value="${redis.pool.maxTotal}" /> <!-- 最大分配的对象数 -->  
  35.         <property name="testOnBorrow" value="${redis.pool.testOnBorrow}" /> <!-- 当调用borrow Object方法时,是否进行有效性检查 -->  
  36.     </bean>  
  37.       
  38.     <!-- ======================单机配置 start ====================== -->  
  39.       
  40.     <!-- spring-data-redis 单机配置 -->  
  41.     <bean id="jedisConnFactory" class="com.huatech.support.redis.RedisSingleConnFactory" >  
  42.          <constructor-arg name="address" value="${spring.redis.single.node}"/>  
  43.          <constructor-arg name="timeout" type="int" value="${spring.redis.single.timeout}" />  
  44.          <constructor-arg name="password" value="${spring.redis.single.password}" />  
  45.          <constructor-arg name="poolConfig" ref="jedisPoolConfig" />  
  46.     </bean>  
  47.       
  48.     <!-- ======================单机配置 end ====================== -->  
  49.       
  50.     <!-- ======================cluster配置 start ====================== -->  
  51.       
  52.     <!-- spring-data-redis-cluster  
  53.     <bean id="redisClusterConfiguration"  class="com.huatech.support.redis.RedisClusterConfig" >  
  54.         <constructor-arg value="${spring.redis.cluster.nodes}"/>  
  55.         <constructor-arg value="${spring.redis.cluster.maxRedirects}" />        
  56.     </bean>  
  57.     <bean id="jedisConnFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" p:use-pool="true">  
  58.          <constructor-arg ref="redisClusterConfiguration" />  
  59.          <constructor-arg ref="jedisPoolConfig" />  
  60.     </bean>  
  61.       -->  
  62.       
  63.       
  64.     <!-- ======================cluster配置 end ====================== -->  
  65.       
  66.     <bean id="stringRedisSerializer" class="org.springframework.data.redis.serializer.StringRedisSerializer" />  
  67.     <bean id ="jdkSerializationRedisSerializer" class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/>   
  68.     <bean id="stringRedisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate"   
  69.         p:connectionFactory-ref="jedisConnFactory" />       
  70.     <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"  
  71.         p:connectionFactory-ref="jedisConnFactory"   
  72.         p:keySerializer-ref="stringRedisSerializer"   
  73.         p:hashKeySerializer-ref="stringRedisSerializer"  
  74.         p:valueSerializer-ref="jdkSerializationRedisSerializer" />  
  75.        
  76. </beans>  

 8、系统中添加缓存支持

Java代码   收藏代码
  1. @Override  
  2. @Cacheable(key="sc:code:{configCode}", expire = 0)  
  3. public SystemConfig findByConfigCode(String configCode) {  
  4.     return systemConfigDao.findByConfigCode(configCode);  
  5. }  

 9、简单测试

Java代码   收藏代码
  1. import org.junit.Test;  
  2. import org.junit.runner.RunWith;  
  3. import org.springframework.test.context.ContextConfiguration;  
  4. import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;  
  5.   
  6. import com.rd.bds.core.common.util.CacheUtils;  
  7.   
  8. @RunWith(SpringJUnit4ClassRunner.class)  
  9. @ContextConfiguration(locations = { "classpath:/spring/spring-config.xml", "classpath:/spring/spring-redis.xml" })  
  10.   
  11. public class CacheUtilsTest {  
  12.   
  13.       
  14.     @Test  
  15.     public void testString()throws Exception{  
  16.         String key = "email";  
  17.         CacheUtils.set(key, "[email protected]", 20);  
  18.         System.out.println(key+":"+CacheUtils.getStr(key));  
  19.         Thread.sleep(1500);  
  20.         System.out.println(key+":"+CacheUtils.getStr(key));  
  21.         Thread.sleep(1500);  
  22.         System.out.println(key+":"+CacheUtils.getStr(key));  
  23.           
  24.     }  
  25.   
  26.       
  27. }  
Java代码   收藏代码
  1. import javax.annotation.Resource;  
  2.   
  3. import org.junit.Test;  
  4. import org.junit.runner.RunWith;  
  5. import org.springframework.test.context.ContextConfiguration;  
  6. import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;  
  7.   
  8. import com.rd.bds.core.service.SystemConfigService;  
  9.   
  10. @RunWith(SpringJUnit4ClassRunner.class)  
  11. @ContextConfiguration(locations = { "classpath:/spring/spring-config.xml", "classpath:/spring/spring-redis.xml" })  
  12. public class SystemConfigServiceImplTest {  
  13.       
  14.     @Resource  
  15.     private SystemConfigService systemConfigService;  
  16.       
  17.     @Test  
  18.     public void test()throws Exception{  
  19.           
  20.         systemConfigService.findByConfigCode("invest_award_limit");  
  21.         Thread.sleep(100L);  
  22.         systemConfigService.findByConfigCode("invest_award_limit");  
  23.         Thread.sleep(100L);  
  24.         systemConfigService.findByConfigCode("invest_award_limit");  
  25.           
  26.     }  
  27.   
  28. }  

猜你喜欢

转载自www.cnblogs.com/zeussbook/p/9296871.html