之前我们说了Spring这个Redis,使用RedisTemplate
实现,不过有些地方也过于麻烦,因此Spring 团队对 Jedis 进行了封装,独立为 spring-data-redis 项目,配合 spring 特性并集成 Jedis 的一些命令和方法。并提供了相关注解,帮助我们快速开发,实现缓存功能
1. 添加项目依赖
<!--redis 缓存-->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>1.8.4.RELEASE</version>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
2.修改spring配置文件
注意:注解的缓存实现需要比Spring方式多配置一个cacheManager
<!-- jedis 配置 -->
<!-- redis连接池的配置 -->
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxTotal" value="100" />
<property name="maxIdle" value="${redis.maxIdle}"/>
<property name="minIdle" value="${redis.minIdle}"/>
<property name="maxWaitMillis" value="${redis.maxWaitMillis}"/>
<property name="testOnBorrow" value="${redis.testOnBorrow}"/>
<property name="testOnReturn" value="${redis.testOnReturn}"/>
</bean>
<!-- redis的连接池pool,不是必选项:timeout/password -->
<bean id="connectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" >
<property name="usePool" value="true"></property>
<property name="hostName" value="${redis.host}" />
<property name="port" value="${redis.port}" />
<property name="password" value="${redis.password}" />
<property name="timeout" value="100000" />
<property name="database" value="0"></property>
<constructor-arg index="0" ref="jedisPoolConfig" />
</bean>
<!-- 配置redis模板,需要注入到 RedisCacheManager by dada -->
<bean id="redisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate">
<property name="connectionFactory" ref="connectionFactory" />
<property name="keySerializer">
<bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />
</property>
<property name="valueSerializer">
<bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" />
</property>
</bean>
<!-- 配置缓存 by dada -->
<bean id="cacheManager" class="org.springframework.data.redis.cache.RedisCacheManager">
<constructor-arg ref="redisTemplate" />
<!--<property name="defaultExpiration" value="300"></property>-->
<property name="usePrefix" value="true"></property>
<property name="expires">
<util:map>
<!-- 指定key的时间为1500秒 -->
<entry key="get_news_notices_list" value="1500"></entry>
<entry key="get_areas_bypid_list" value="1500"></entry>
</util:map>
</property>
</bean>
由于使用的是spring提供的注解方式实现redis缓存,所以需要在spring配置文件加上cache标签,否则注解不会生效。如果注解是使用在Controller层,需要SpringMVC配置文件也要加上
<!-- 启用缓存注解功能,这个是必须的,否则注解不会生效,另外,该注解一定要声明在spring主配置文件中才会生效,这个cacheManager
必须指向redis配置里面的 RedisCacheManager-->
<cache:annotation-driven cache-manager="cacheManager" />
3.注解介绍
- @CacheConfig 配置在类上,cacheNames即定义了本类中所有用到缓存的地方,都去找这个库。只要使用了这个注解,在方法上@Cacheable @CachePut @CacheEvict就可以不用写value去找具体库名了。【一般不怎么用】
- @Cacheable 配置在方法或类上,作用:本方法执行后,先去缓存看有没有数据,如果没有,从数据库中查找出来,给缓存中存一份,返回结果会将方法的返回值作为value进行缓存,下次本方法执行,在缓存未过期情况下,先在缓存中查找,有的话直接返回,没有的话从数据库查找
- @CachePut 类似于更新操作,即每次不管缓存中有没有结果,都从数据库查找结果,并将结果更新到缓存,并返回结果
- @CacheEvict 用来清除用在本方法或者类上的缓存数据(用在哪里清除哪里)
总结
- 我们在类上使用了
@CacheConfig
注解,则相当于声明缓存到哪个数据库,则下面的方法中使用@Cacheable
则不需要使用value
属性. @Cacheable
中使用key
属性指定我们redis的key值,支持SPEL
表达式,也就是我们可以使用方法的参数来当做key
,同样Spring团队Spring还为我们提供了一个root对象可以用来生成key。通过该root对象我们可以获取到以下信息。
属性名称 | 描述 | 示例 |
---|---|---|
methodName | 当前方法名 | #root.methodName |
method | 当前方法 | #root.method.name |
target | 当前被调用的对象 | #root.target |
targetClass | 当前被调用的对象的class | #root.targetClass |
args | 当前方法参数组成的数组 | #root.args[0] |
caches | 当前被调用的方法使用的Cache | #root.caches[0].name |
同样如果我们没有在@Cacheable
中指定key的属性,则会使用默认我们自定义的key生成规则
在我们的redis配置文件中增加配置
<!-- 配置RedisCacheConfig -->
<bean id="redisCacheConfig" class="com.yz.redis.RedisCacheConfig">
<constructor-arg ref="connectionFactory"/>
<constructor-arg ref="redisTemplate"/>
<constructor-arg ref="cacheManager"/>
</bean>
@Configuration
@EnableCaching
public class RedisCacheConfig extends CachingConfigurerSupport {
protected final static Logger log = LoggerFactory.getLogger(RedisCacheConfig.class);
private volatile JedisConnectionFactory mJedisConnectionFactory;
private volatile RedisTemplate<String, String> mRedisTemplate;
private volatile RedisCacheManager mRedisCacheManager;
public RedisCacheConfig() {
super();
}
public RedisCacheConfig(JedisConnectionFactory mJedisConnectionFactory, RedisTemplate<String, String> mRedisTemplate, RedisCacheManager mRedisCacheManager) {
super();
this.mJedisConnectionFactory = mJedisConnectionFactory;
this.mRedisTemplate = mRedisTemplate;
this.mRedisCacheManager = mRedisCacheManager;
}
public JedisConnectionFactory redisConnectionFactory() {
return mJedisConnectionFactory;
}
public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory cf) {
return mRedisTemplate;
}
public CacheManager cacheManager(RedisTemplate<?, ?> redisTemplate) {
return mRedisCacheManager;
}
@Bean
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
@Override
public Object generate(Object o, Method method, Object... objects) {
StringBuilder sb = new StringBuilder();
sb.append(o.getClass().getName());
sb.append(method.getName());
for (Object obj : objects) {
sb.append(obj.toString());
}
return sb.toString();
}
};
}
}
该配置类继承自 org.springframework.cache.annotation.CachingConfigurerSupport
并实现 org.springframework.cache.annotation.CachingConfigurer
的方法。
4.示例
@Cacheable(value = "get_news_notices_list",key = "'newsNotice'+#userNo.concat(#typeSn)")
@ResponseBody
@RequestMapping("/ajaxListVo")
public String ajaxListVo(NewsNotice notice, Query query,String typeSn,HttpServletRequest request, HttpServletResponse response,String userNo) {
//业务逻辑
我们声明缓存的数据库为get_news_notices_list
,并需要在配置文件中指定以及过期时间
<entry key="get_news_notices_list" value="1500"></entry>
缓存的key使用SPEL表达式对参数进行取值'newsNotice'+#userNo.concat(#typeSn)
为字符串newsNotice加上我们参数userNo以及typeSn
首先我们的数据库中缓存是没有的
当我们访问接口的时候,发现缓存中没有相关的key,于是访问数据库,并将方法结果缓存到redis
此时我们使用monitor
命令监控,发现数据确实缓存到redis服务器中了
当我们再次访问接口的时候,已经是从缓存拿数据了~~