gpt4 book ai didi

浅谈SpringCache与redis集成实现缓存解决方案

转载 作者:qq735679552 更新时间:2022-09-27 22:32:09 26 4
gpt4 key购买 nike

CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.

这篇CFSDN的博客文章浅谈SpringCache与redis集成实现缓存解决方案由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.

缓存可以说是加速服务响应速度的一种非常有效并且简单的方式。在缓存领域,有很多知名的框架,如ehcache 、guava、hazelcast等。redis作为key-value型数据库,由于他的这一特性,redis也成为一种流行的数据缓存工具.

在传统方式下对于缓存的处理代码是非常臃肿的.

例如:我们要把一个查询函数加入缓存功能,大致需要三步.

1、在函数执行前,我们需要先检查缓存中是否存在数据,如果存在则返回缓存数据 。

2、如果不存在,就需要在数据库的数据查询出来.

3、最后把数据存放在缓存中,当下次调用此函数时,就可以直接使用缓存数据,减轻了数据库压力.

那么实现上面的三步需要多少代码呢?下面是一个示例:

    。

上图中的红色部分都是模板代码,真正与这个函数有关的代码却只占了1/5,对于所有需要实现缓存功能的函数,都需要加上臃肿的模板代码。可谓是一种极不优雅的解决方案.

那么如何让臃肿的代码重回清新的当初呢?

aop不就是专门解决这种模板式代码的最佳方案吗,幸运的是我们不需要再自己实现切面了,springcache已经为我们提供好了切面,我们只需要进行简单的配置,就可以重回当初了,像下面这样:

浅谈SpringCache与redis集成实现缓存解决方案  

只需要加一个注解就可以了,对于原来的代码连改都不需要改,是不是已经跃跃欲试了?

对于配置springcache只需要三步:

第一步:加入相关依赖:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<dependency>
   <groupid>redis.clients</groupid>
   <artifactid>jedis</artifactid>
  <version> 2.9 . 0 </version>
</dependency>
<dependency>
   <groupid>org.springframework.data</groupid>
   <artifactid>spring-data-redis</artifactid>
   <version> 1.6 . 0 .release</version>
</dependency>
<dependency>
  <groupid>org.apache.commons</groupid>
  <artifactid>commons-lang3</artifactid>
  <version> 3.3 . 2 </version>
</dependency>

第二步:配置springcache,redis连接等信息 。

applicationcontext-redis.xml 。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<?xml version= "1.0" encoding= "utf-8" ?>
<beans xmlns= "http://www.springframework.org/schema/beans"
   xmlns:xsi= "http://www.w3.org/2001/xmlschema-instance" xmlns:p= "http://www.springframework.org/schema/p"
   xmlns:context= "http://www.springframework.org/schema/context"
   xmlns:mvc= "http://www.springframework.org/schema/mvc"
   xmlns:cache= "http://www.springframework.org/schema/cache"
   xsi:schemalocation="http: //www.springframework.org/schema/beans  
             http: //www.springframework.org/schema/beans/spring-beans-4.2.xsd  
             http: //www.springframework.org/schema/context  
             http: //www.springframework.org/schema/context/spring-context-4.2.xsd  
             http: //www.springframework.org/schema/mvc  
             http: //www.springframework.org/schema/mvc/spring-mvc-4.2.xsd
             http: //www.springframework.org/schema/cache 
             http: //www.springframework.org/schema/cache/spring-cache-4.2.xsd">
  
  <!-- 配置文件加载 -->
  <context:property-placeholder location= "classpath:*.properties" />
<cache:annotation-driven cache-manager= "cachemanager" />
   <!-- redis连接池 -->
   <bean id= "poolconfig" class = "redis.clients.jedis.jedispoolconfig" >
     <property name= "maxidle" value= "${redis.maxidle}" />  
      <property name= "maxwaitmillis" value= "${redis.maxwait}" /> 
      <property name= "testonborrow" value= "${redis.testonborrow}" />
   </bean>
   <!-- 连接工厂 -->
   <bean id= "jedisconnectionfactory" class = "org.springframework.data.redis.connection.jedis.jedisconnectionfactory"
     p:host-name= "${redis.host}" p:port= "${redis.port}" p:password= "${redis.pass}" p:pool-config-ref= "poolconfig" />
   <!-- redis模板 -->
   <bean id= "redistemplate" class = "org.springframework.data.redis.core.redistemplate"
      <property name= "connectionfactory" ref= "jedisconnectionfactory" /> 
   </bean>
   
   <bean id= "cachemanager" class = "org.springframework.cache.support.simplecachemanager"
      <property name= "caches"
       <set> 
         <!-- 这里可以配置多个redis -->
         <bean class = "com.cky.rest.utils.rediscache"
            <property name= "redistemplate" ref= "redistemplate" /> 
            <property name= "name" value= "content" /> 
            <!-- name对应的名称要在类或方法的注解中使用 -->
         </bean>
       </set> 
      </property> 
    </bean> 
</beans>

redis.properties文件:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# redis settings
# server ip
redis.host= 192.168 . 100.55
# server port
redis.port= 6379
# server pass
redis.pass=
# use dbindex
redis.database= 0
#max idel instance of jedis
redis.maxidle= 300
# if wait too long , throw jedisconnectionexception
redis.maxwait= 3000
# if true ,it will validate before borrow jedis instance,what you get instance is all usefull
redis.testonborrow= true

第三步,编写cache接口实现类 。

spring对于缓存只是提供了抽象的接口,并且通过接口来调用功能,没有具体的实现类,所以需要我们自己实现具体的操作.

在上面配置中可知,每个实现类都会注入一个redistemplate实例,我们就可以通过redistemplate来操作redis 。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
package com.cky.rest.utils;
import java.io.serializable;
import org.apache.commons.lang3.serializationutils;
import org.springframework.cache.cache;
import org.springframework.cache.support.simplevaluewrapper;
import org.springframework.dao.dataaccessexception;
import org.springframework.data.redis.connection.redisconnection;
import org.springframework.data.redis.core.rediscallback;
import org.springframework.data.redis.core.redistemplate;
public class rediscache implements cache {
 
   private redistemplate<string, object> redistemplate;
   private string name;
 
   @override
   public void clear() {
     system.out.println( "-------緩存清理------" );
     redistemplate.execute( new rediscallback<string>() {
       @override
       public string doinredis(redisconnection connection) throws dataaccessexception {
         connection.flushdb();
         return "ok" ;
       }
     });
   }
 
   @override
   public void evict(object key) {
     system.out.println( "-------緩存刪除------" );
     final string keyf=key.tostring();
     redistemplate.execute( new rediscallback< long >() {
       @override
       public long doinredis(redisconnection connection) throws dataaccessexception {
         return connection.del(keyf.getbytes());
       }
      
     });
 
   }
 
   @override
   public valuewrapper get(object key) {
     system.out.println( "------缓存获取-------" +key.tostring());
     final string keyf = key.tostring();
     object object = null ;
     object = redistemplate.execute( new rediscallback<object>() {
       @override
       public object doinredis(redisconnection connection) throws dataaccessexception {
         byte [] key = keyf.getbytes();
         byte [] value = connection.get(key);
         if (value == null ) {
           system.out.println( "------缓存不存在-------" );
           return null ;
         }
         return serializationutils.deserialize(value);
       }
     });
     valuewrapper obj=(object != null ? new simplevaluewrapper(object) : null );
     system.out.println( "------获取到内容-------" +obj);
     return obj;
   }
 
   @override
   public void put(object key, object value) {
     system.out.println( "-------加入缓存------" );
     system.out.println( "key----:" +key);
     system.out.println( "key----:" +value);
     final string keystring = key.tostring();
     final object valuef = value;
     final long livetime = 86400 ;
     redistemplate.execute( new rediscallback< long >() {
       @override
       public long doinredis(redisconnection connection) throws dataaccessexception {
         byte [] keyb = keystring.getbytes();
         byte [] valueb = serializationutils.serialize((serializable) valuef);
         connection.set(keyb, valueb);
         if (livetime > 0 ) {
           connection.expire(keyb, livetime);
         }
         return 1l;
       }
     });
 
   }
  
   @override
   public <t> t get(object arg0, class <t> arg1) {
     // todo auto-generated method stub
     return null ;
   }
  
   @override
   public string getname() {
     return this .name;
   }
 
   @override
   public object getnativecache() {
     return this .redistemplate;
   }
  
   @override
   public valuewrapper putifabsent(object arg0, object arg1) {
     // todo auto-generated method stub
     return null ;
   }
 
   public redistemplate<string, object> getredistemplate() {
     return redistemplate;
   }
 
   public void setredistemplate(redistemplate<string, object> redistemplate) {
     this .redistemplate = redistemplate;
   }
 
   public void setname(string name) {
     this .name = name;
   }
}

在配置过程中曾经出现过两次错误:

1.xxxx.classnotfoundexception 最后发现是jar下载不完整,把maven本地仓库的对应jar包文件夹删除完从新下载就好了 。

2.xxxx.methodnotfoundexception 这种情况是版本不对,换成第一步中的版本就可以了 。

springcache中常见注解的使用:

@cacheable注解 。

最常用的注解,会把被注解方法的返回值缓存。工作原理是:首先在缓存中查找,如果没有执行方法并缓存结果,然后返回数据。此注解的缓存名必须指定,和cachemanager中的caches中的某一个cache的name值相对应。可以使用value或cachenames指定.

如果没有指定key属性,spring会使用默认的主键生成器产生主键。也可以自定义主键,在key中可以使用spel表达式。如下:

?
1
2
3
4
@cacheable (cachenames=”content”,key=”#user.userid”)
public user getuser(user user){
   xxxxx
}

可以使用condition属性,来给缓存添加条件,如下:

?
1
2
@cacheable (cachenames=”content”,key=”#user.userid”,condition=”#user.age< 40 ”)
public user getuser(user user){xxxxx}

@cacheput注解 。

先执行方法,然后将返回值放回缓存。可以用作缓存的更新.

@cacheevict注解 。

该注解负责从缓存中显式移除数据,通常缓存数据都有有效期,当过期时数据也会被移除.

此注解多了两个属性:

allentries是否移除所有缓存条目.

beforeinvocation:在方法调用前还是调用后完成移除操作。true/false 。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我.

原文链接:http://www.cnblogs.com/chenkeyu/p/8028781.html 。

最后此篇关于浅谈SpringCache与redis集成实现缓存解决方案的文章就讲到这里了,如果你想了解更多关于浅谈SpringCache与redis集成实现缓存解决方案的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com