zoukankan      html  css  js  c++  java
  • 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. }  

    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, "lh@erongdu.com", 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. }  
  • 相关阅读:
    Java关键字new和newInstance的区别
    关于能提高Java代码可重用性的三个措施
    Java编程技巧—— JDBC编程总结
    Java高质量代码之数组与集合
    ab的压力测试(转)
    利用DOCKER实现云桌面的开发环境初步设想
    时间和日期
    内存流-操作文件的方式操作内存
    获取文件描述符
    流定位
  • 原文地址:https://www.cnblogs.com/zeussbook/p/9296871.html
Copyright © 2011-2022 走看看