• spring与redis集成之aop整合方案


    java使用redis缓存可以使用jedis框架,jedis操作简单,没有什么复杂的东西需要学习,网上资料很多,随便看看就会了.

    将spring与redis缓存集成,其实也是使用jedis框架,只不过spring对它进行了一层封装,并将这层封装库命名为spring-data-redis.

    下面将要使用spring-data-redis与jedis的jar包,并通过spring的aop功能,将redis缓存无缝无侵入的整合进来.

    1.先下载好依赖包

    [html] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. <dependency>  
    2.     <groupId>org.springframework</groupId>  
    3.     <artifactId>spring-core</artifactId>  
    4.     <version>4.1.1.RELEASE</version>  
    5. </dependency>  
    6. <!-- 还有spring的其它包,这里不一一贴出-->  
    [html] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. <dependency>    
    2.     <groupId>org.springframework.data</groupId>    
    3.     <artifactId>spring-data-redis</artifactId>    
    4.     <version>1.4.1.RELEASE</version>    
    5. </dependency>   
    6. <dependency>   
    7.     <groupId>redis.clients</groupId>   
    8.     <artifactId>jedis</artifactId>   
    9.     <version>2.6.0</version>   
    10. </dependency>   


    2.再配置spring文件

    [html] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1.    <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">  
    2.     <property name="minIdle" value="${redis.minIdle}" />  
    3.        <property name="maxIdle" value="${redis.maxIdle}" />    
    4.        <property name="maxTotal" value="${redis.maxActive}" />    
    5.        <property name="maxWaitMillis" value="${redis.maxWait}" />    
    6.        <property name="testOnBorrow" value="${redis.testOnBorrow}" />    
    7.    </bean>    
    8.      
    9.    <bean id="jedisConnFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">  
    10.        <property name="hostName" value="${redis.host}" />  
    11.        <property name="port" value="${redis.port}" />  
    12.        <property name="password" value="${redis.password}" />  
    13.        <property name="usePool" value="true" />  
    14.        <property name="poolConfig" ref="poolConfig" />  
    15.    </bean>   
    16.      
    17. <!-- redis template definition -->  
    18. <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">  
    19.     <property name="connectionFactory" ref="jedisConnFactory" />  
    20.     <property name="keySerializer">  
    21.         <bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />  
    22.     </property>     
    23.     <property name="valueSerializer">  
    24.         <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" />  
    25.     </property>  
    26.     <property name="hashKeySerializer">    
    27.        <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>    
    28.     </property>  
    29.     <property name="hashValueSerializer">  
    30.        <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/>    
    31.     </property>  
    32. </bean>  


    3.开始编写aop代码

    3.1 声明两个注解类,用于定义哪些方法将使用缓存

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. @Retention(RetentionPolicy.RUNTIME)  
    2. @Target({ElementType.METHOD})  
    3. public @interface Cacheable {  
    4.       
    5.     public enum KeyMode{  
    6.         DEFAULT,    //只有加了@CacheKey的参数,才加入key后缀中  
    7.         BASIC,      //只有基本类型参数,才加入key后缀中,如:String,Integer,Long,Short,Boolean  
    8.         ALL;        //所有参数都加入key后缀  
    9.     }  
    10.       
    11.     public String key() default "";     //缓存key  
    12.     public KeyMode keyMode() default KeyMode.DEFAULT;       //key的后缀模式  
    13.     public int expire() default 0;      //缓存多少秒,默认无限期  
    14. }  
    [java] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. @Retention(RetentionPolicy.RUNTIME)  
    2. @Target({ElementType.PARAMETER})  
    3. public @interface CacheKey {}  

    3.2 创建一个Aop拦截器的处理类,用于拦截加了@Cacheable的方法

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. @Aspect  
    2. @Component  
    3. public class CacheableAop {  
    4.       
    5.     @Autowired private RedisTemplate redisTemplate;  
    6.       
    7.     @Around("@annotation(cache)")  
    8.     public Object cached(final ProceedingJoinPoint pjp,Cacheable cache) throws Throwable {  
    9.           
    10.         String key=getCacheKey(pjp, cache);  
    11.         ValueOperations<String, Object> valueOper=redisTemplate.opsForValue();  
    12.         Object value=valueOper.get(key);    //从缓存获取数据  
    13.         if(value!=null) return value;       //如果有数据,则直接返回  
    14.           
    15.         value = pjp.proceed();      //跳过缓存,到后端查询数据  
    16.         if(cache.expire()<=0) {      //如果没有设置过期时间,则无限期缓存  
    17.             valueOper.set(key, value);  
    18.         } else {                    //否则设置缓存时间  
    19.             valueOper.set(key, value,cache.expire(),TimeUnit.SECONDS);  
    20.         }  
    21.         return value;  
    22.     }  
    23.       
    24.     /** 
    25.      * 获取缓存的key值 
    26.      * @param pjp 
    27.      * @param cache 
    28.      * @return 
    29.      */  
    30.     private String getCacheKey(ProceedingJoinPoint pjp,Cacheable cache) {  
    31.           
    32.         StringBuilder buf=new StringBuilder();  
    33.         buf.append(pjp.getSignature().getDeclaringTypeName()).append(".").append(pjp.getSignature().getName());  
    34.         if(cache.key().length()>0) {  
    35.             buf.append(".").append(cache.key());  
    36.         }  
    37.           
    38.         Object[] args=pjp.getArgs();  
    39.         if(cache.keyMode()==KeyMode.DEFAULT) {  
    40.             Annotation[][] pas=((MethodSignature)pjp.getSignature()).getMethod().getParameterAnnotations();  
    41.             for(int i=0;i<pas.length;i++) {  
    42.                 for(Annotation an:pas[i]) {  
    43.                     if(an instanceof CacheKey) {  
    44.                         buf.append(".").append(args[i].toString());  
    45.                         break;  
    46.                     }  
    47.                 }  
    48.             }  
    49.         } else if(cache.keyMode()==KeyMode.BASIC) {  
    50.             for(Object arg:args) {  
    51.                 if(arg instanceof String) {  
    52.                     buf.append(".").append(arg);  
    53.                 } else if(arg instanceof Integer || arg instanceof Long || arg instanceof Short) {  
    54.                     buf.append(".").append(arg.toString());  
    55.                 } else if(arg instanceof Boolean) {  
    56.                     buf.append(".").append(arg.toString());  
    57.                 }  
    58.             }  
    59.         } else if(cache.keyMode()==KeyMode.ALL) {  
    60.             for(Object arg:args) {  
    61.                 buf.append(".").append(arg.toString());  
    62.             }  
    63.         }  
    64.           
    65.         return buf.toString();  
    66.     }  
    67. }  

    4.使用缓存示例

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. @Service  
    2. @Transactional  
    3. public class DemoServiceImpl implements DemoService {  
    4.   
    5.     @Autowired private DemoDao demoDao;  
    6.   
    7.     public List<Demo> findAll() {  
    8.         return demoDao.findAll();  
    9.     }  
    10.       
    11.     /* 
    12.         对get()方法配置使用缓存,缓存有效期为3600秒,缓存的key格式为:{package_name}.DemoServiceImpl.get 
    13.         同时为参数配置了@CacheKey后,表示此参数的值将做为key的后缀,此例的key,最终是:{package_name}.DemoServiceImpl.get.{id} 
    14.         可以为多个参数配置@CacheKey,拦截器会调用参数的toString()做为key的后缀 
    15.         若配置多个@CacheKey参数,那么最终的key格式为:{package_name}.{class_name}.{method}.{arg1}.{arg2}.{...} 
    16.      */  
    17.     @Cacheable(expire=3600)  
    18.     public Demo get(@CacheKey String id) {  
    19.         return demoDao.get(id);  
    20.     }  
    21.   
    22.     public Demo getByName(String name) {  
    23.         return demoDao.getByName(name);  
    24.     }  
    25. }  
    • 若为名称相同的方法配置缓存,可以在@Cacheable中加入key属性,追加额外的key后缀
    • @Cacheable还有一个KeyMode属性,用于配置哪些参数可以追加到key后缀中,
      默认取值 DEFAULT:表示只有加了@CacheKey的参数才能追加到key后缀
      BASIC:自动将基本类型追加到key后缀,而无需再配置@CacheKey
      ALL:自动将所有参数追加到lkey后缀,而无需再配置@CacheKey

    这只是一个初步整合方案,测试可行,还未在生产中使用,实际效果待验正.

  • 相关阅读:
    剑指Offer-11.二进制中1的个数(C++/Java)
    剑指Offer-10.矩形覆盖(C++/Java)
    剑指Offer-9.变态跳台阶(C++/Java)
    UVA 1608 Non-boring sequence 不无聊的序列(分治,中途相遇)
    UVA1607 Gates 与非门电路 (二分)
    UVA 1451 Average平均值 (数形结合,斜率优化)
    UVA 1471 Defense Lines 防线 (LIS变形)
    UVA 1606 Amphiphilic Carbon Molecules 两亲性分子 (极角排序或叉积,扫描法)
    UVA 11134 FabledRooks 传说中的车 (问题分解)
    UVA 1152 4 Values Whose Sum is Zero 和为0的4个值 (中途相遇)
  • 原文地址:https://www.cnblogs.com/lijc1990/p/4250915.html
Copyright © 2020-2023  润新知