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

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

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

1.先下载好依赖包


[html] 


1. <dependency>  
2. <groupId>org.springframework</groupId>  
3. <artifactId>spring-core</artifactId>  
4. <version>4.1.1.RELEASE</version>  
5. </dependency>  
6. <!-- 还有spring的其它包,这里不一一贴出-->

[html] 

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] 

    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]

     

    1. @Retention(RetentionPolicy.RUNTIME)  
    2. @Target({ElementType.METHOD})  
    3. public @interface Cacheable {  
    4.       
    5. public enum KeyMode{  
    6. //只有加了@CacheKey的参数,才加入key后缀中  
    7. //只有基本类型参数,才加入key后缀中,如:String,Integer,Long,Short,Boolean  
    8. //所有参数都加入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]

     

    1. @Retention(RetentionPolicy.RUNTIME)  
    2. @Target({ElementType.PARAMETER})  
    3. public @interface CacheKey {}

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

    [java] 

      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. //从缓存获取数据  
      13. if(value!=null) return value;       //如果有数据,则直接返回  
      14.           
      15. //跳过缓存,到后端查询数据  
      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. new StringBuilder();  
      33. ".").append(pjp.getSignature().getName());  
      34. if(cache.key().length()>0) {  
      35. ".").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. ".").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. ".").append(arg);  
      53. else if(arg instanceof Integer || arg instanceof Long || arg instanceof Short) {  
      54. ".").append(arg.toString());  
      55. else if(arg instanceof Boolean) {  
      56. ".").append(arg.toString());  
      57.                 }  
      58.             }  
      59. else if(cache.keyMode()==KeyMode.ALL) {  
      60. for(Object arg:args) {  
      61. ".").append(arg.toString());  
      62.             }  
      63.         }  
      64.           
      65. return buf.toString();  
      66.     }  
      67. }


      4.使用缓存示例

      [java] 

      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

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