Spring整合Redis註解實現
之前我們說了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伺服器中了
當我們再次訪問介面的時候,已經是從快取拿資料了~~