1. 程式人生 > >Spring整合Redis註解實現

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.註解介紹

  1. @CacheConfig 配置在類上,cacheNames即定義了本類中所有用到快取的地方,都去找這個庫。只要使用了這個註解,在方法上@Cacheable @CachePut @CacheEvict就可以不用寫value去找具體庫名了。【一般不怎麼用】
  2. @Cacheable 配置在方法或類上,作用:本方法執行後,先去快取看有沒有資料,如果沒有,從資料庫中查找出來,給快取中存一份,返回結果會將方法的返回值作為value進行快取,下次本方法執行,在快取未過期情況下,先在快取中查詢,有的話直接返回,沒有的話從資料庫查詢
  3. @CachePut 類似於更新操作,即每次不管快取中有沒有結果,都從資料庫查詢結果,並將結果更新到快取,並返回結果
  4. @CacheEvict 用來清除用在本方法或者類上的快取資料(用在哪裡清除哪裡)

總結

  1. 我們在類上使用了@CacheConfig 註解,則相當於宣告快取到哪個資料庫,則下面的方法中使用@Cacheable 則不需要使用value 屬性.
  2. @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伺服器中了
在這裡插入圖片描述

當我們再次訪問介面的時候,已經是從快取拿資料了~~