spring cache使用redis作緩存

程序員

在這裏就不作spring框架詳細描述,只對用的做解釋,有什麼問題歡迎來信。

1.pom添加

這裏增長spring-data-redisjedis 必需要jar包。java

<dependency>
			<groupId>org.springframework.data</groupId>
			<artifactId>spring-data-redis</artifactId>
			<version>1.3.4.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>redis.clients</groupId>
			<artifactId>jedis</artifactId>
			<version>2.5.2</version>
		</dependency>

2.spring 配置

在spring的配置文件applicationContext.xml里加入下面的redis的配置信息。程序員

<!-- redis配置 -->
		<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">  
	        <property name="maxIdle" value="300" />  
	        <property name="maxTotal" value="600" />  
	        <property name="maxWaitMillis" value="1000" />  
	        <property name="testOnBorrow" value="true" />  
	    </bean>
	    
	    <bean id="connectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"  
        	p:host-name="192.168.31.4" p:port="6379" p:password=""  p:pool-config-ref="poolConfig"/>

		<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">  
	        <property name="connectionFactory" ref="connectionFactory" />
	    </bean>

這裏配置redis的一些信息,固然也能夠用配置文件來配置redis

redis.host=192.168.31.4 
redis.port=6379  
redis.pass= 
redis.maxIdle=50  
redis.maxActive=50  
redis.maxWait=50  
redis.testOnBorrow=true  
redis.timeout=1000

接下來在配置文件中配置要緩存的對象值,以下:spring

<cache:annotation-driven/>
	<!-- 緩存管理器 -->
	<bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
		<property name="caches">
			<set>
				<bean class="com.hejia.alauda.redis.SystemRedisCache">
					<property name="redisTemplate" ref="redisTemplate" />
					<property name="name" value="default" />
					<property name="timeout" value="600" /><!-- 10分鐘後過時 -->
				</bean>
				<bean class="com.hejia.alauda.redis.SystemRedisCache">
					<property name="redisTemplate" ref="redisTemplate" />
					<property name="name" value="orderServiceImpl.selectInterests" />
					<property name="timeout" value="600" />
				</bean>
				<bean class="com.hejia.alauda.redis.SystemRedisCache">
					<property name="redisTemplate" ref="redisTemplate" />
					<property name="name" value="orderServiceImpl.selectInterestsList" />
					<property name="timeout" value="600" />
				</bean>
			</set>
		</property>
	</bean>

這裏面配置的orderServiceImpl.selectInterestsorderServiceImpl.selectInterestsList 分別是redis緩存的名稱,下面代碼會說到數據庫

3.redis緩存配置類

這裏增長配置文件中實現的SystemRedisCache ,這裏主要對redis的業務的操做方法。數組

import com.hejia.alauda.utils.SerializableUtil;
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;
import org.springframework.util.StringUtils;

/**
 * info:redis緩存配置類
 * Created by shang on 2016/11/9.
 */
public class SystemRedisCache implements Cache {

    /**
     * Redis
     */
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 緩存名稱
     */
    private String name;

    /**
     * 超時時間
     */
    private long timeout;

    /*
     * (non-Javadoc)
     * @see org.springframework.cache.Cache#getName()
     */
    @Override
    public String getName() {
        return this.name;
    }

    /*
     * (non-Javadoc)
     * @see org.springframework.cache.Cache#getNativeCache()
     */
    @Override
    public Object getNativeCache() {
        // TODO Auto-generated method stub
        return this.redisTemplate;
    }

    /*
     * (non-Javadoc)
     * @see org.springframework.cache.Cache#get(java.lang.Object)
     */
    @Override
    public ValueWrapper get(Object key) {
        if (StringUtils.isEmpty(key)) {
            return null;
        } else {
            final String finalKey;
            if (key instanceof String) {
                finalKey = (String) key;
            } else {
                finalKey = key.toString();
            }
            Object object = null;
            object = redisTemplate.execute(new RedisCallback<Object>() {
                public Object doInRedis(RedisConnection connection) throws DataAccessException {
                    byte[] key = finalKey.getBytes();
                    byte[] value = connection.get(key);
                    if (value == null) {
                        return null;
                    }
                    return SerializableUtil.unserialize(value);
                }
            });
            return (object != null ? new SimpleValueWrapper(object) : null);
        }
    }

    /*
     * (non-Javadoc)
     * @see org.springframework.cache.Cache#get(java.lang.Object, java.lang.Class)
     */
    @SuppressWarnings("unchecked")
    @Override
    public <T> T get(Object key, Class<T> type) {
        if (StringUtils.isEmpty(key) || null == type) {
            return null;
        } else {
            final String finalKey;
            final Class<T> finalType = type;
            if (key instanceof String) {
                finalKey = (String) key;
            } else {
                finalKey = key.toString();
            }
            final Object object = redisTemplate.execute(new RedisCallback<Object>() {
                public Object doInRedis(RedisConnection connection) throws DataAccessException {
                    byte[] key = finalKey.getBytes();
                    byte[] value = connection.get(key);
                    if (value == null) {
                        return null;
                    }
                    return SerializableUtil.unserialize(value);
                }
            });
            if (finalType != null && finalType.isInstance(object) && null != object) {
                return (T) object;
            } else {
                return null;
            }
        }
    }

    /*
     * (non-Javadoc)
     * @see org.springframework.cache.Cache#put(java.lang.Object, java.lang.Object)
     */
    @Override
    public void put(final Object key, final Object value) {
        if (StringUtils.isEmpty(key) || StringUtils.isEmpty(value)) {
            return;
        } else {
            final String finalKey;
            if (key instanceof String) {
                finalKey = (String) key;
            } else {
                finalKey = key.toString();
            }
            if (!StringUtils.isEmpty(finalKey)) {
                final Object finalValue = value;
                redisTemplate.execute(new RedisCallback<Boolean>() {
                    @Override
                    public Boolean doInRedis(RedisConnection connection) {
                        connection.set(finalKey.getBytes(), SerializableUtil.serialize(finalValue));
                        // 設置超時間
                        connection.expire(finalKey.getBytes(), timeout);
                        return true;
                    }
                });
            }
        }
    }

    /*
     * 根據Key 刪除緩存
     */
    @Override
    public void evict(Object key) {
        if (null != key) {
            final String finalKey;
            if (key instanceof String) {
                finalKey = (String) key;
            } else {
                finalKey = key.toString();
            }
            if (!StringUtils.isEmpty(finalKey)) {
                redisTemplate.execute(new RedisCallback<Long>() {
                    public Long doInRedis(RedisConnection connection) throws DataAccessException {
                        return connection.del(finalKey.getBytes());
                    }
                });
            }
        }
    }

    /*
     * 清楚系統緩存
     */
    @Override
    public void clear() {
        // TODO Auto-generated method stub
        // redisTemplate.execute(new RedisCallback<String>() {
        // public String doInRedis(RedisConnection connection) throws DataAccessException {
        // connection.flushDb();
        // return "ok";
        // }
        // });
    }

    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;
    }

    public long getTimeout() {
        return timeout;
    }

    public void setTimeout(long timeout) {
        this.timeout = timeout;
    }
}

這裏附帶一個工具類的代碼,主要對開發中object和list對象的序列化和反序列化。 由於redis不知object和泛型,全部在將對象存入redis時,須要將緩存的數據序列化。緩存

import java.io.*;
import java.util.ArrayList;
import java.util.List;

/**
 * info:序列化工具類
 * Created by shang on 2016/11/9.
 */
public class SerializableUtil {

    /**
     * 序列化
     *
     * @param object
     * @return
     */
    public static byte[] serialize(Object object) {
        if (object == null) {
            return null;
        }
        ObjectOutputStream oos = null;
        ByteArrayOutputStream baos = null;
        byte[] bytes = null;
        try {
            // 序列化
            baos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(baos);
            oos.writeObject(object);
            bytes = baos.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(oos);
            close(baos);
        }
        return bytes;
    }

    /**
     * 反序列化
     *
     * @param bytes
     * @return
     */
    public static Object unserialize(byte[] bytes) {
        if (bytes == null) {
            return null;
        }
        ByteArrayInputStream bais = null;
        ObjectInputStream ois = null;
        try {
            // 反序列化
            bais = new ByteArrayInputStream(bytes);
            ois = new ObjectInputStream(bais);
            return ois.readObject();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(bais);
            close(ois);
        }
        return null;
    }

    /**
     * 序列化 list 集合
     *
     * @param list
     * @return
     */
    public static byte[] serializeList(List<?> list) {

        if (list==null||list.size()==0) {
            return null;
        }
        ObjectOutputStream oos = null;
        ByteArrayOutputStream baos = null;
        byte[] bytes = null;
        try {
            baos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(baos);
            for (Object obj : list) {
                oos.writeObject(obj);
            }
            bytes = baos.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(oos);
            close(baos);
        }
        return bytes;
    }

    /**
     * 反序列化 list 集合
     */
    public static List<?> unserializeList(byte[] bytes) {
        if (bytes == null) {
            return null;
        }

        List<Object> list = new ArrayList<Object>();
        ByteArrayInputStream bais = null;
        ObjectInputStream ois = null;
        try {
            // 反序列化
            bais = new ByteArrayInputStream(bytes);
            ois = new ObjectInputStream(bais);
            while (bais.available() > 0) {
                Object obj = (Object) ois.readObject();
                if (obj == null) {
                    break;
                }
                list.add(obj);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(bais);
            close(ois);
        }
        return list;
    }

    /**
     * 關閉io流對象
     *
     * @param closeable
     */
    public static void close(Closeable closeable) {
        if (closeable != null) {
            try {
                closeable.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}

4.緩存service方法

對指定的service方法作緩存,使用方法以下:app

@Cacheable(value = "orderServiceImpl.selectInterests",key = "'selectInterests_'+#params.get('user_id')+'_'+#params.get('type')+'_'+#pager.pageNumber")//增長redis緩存
    @Override
	public Pager<Interest> selectInterests(Map<String, Object> params, Pager<Interest> pager) {
        System.out.println("select selectInterests class ....");
        pager.setList(interestMapper.findInterestListV3(params, pager));
		pager.setTotalCount(interestMapper.findCountInterestListV3(params));
		return pager;
	}

	@Cacheable(value = "orderServiceImpl.selectInterestsList",key = "'selectInterestsList_'+#params.get('user_id')+'_'+#params.get('type')+'_'+#params.get('valueDate')")//增長redis緩存
    @Override
    public List<Map<String, Object>> selectInterestsList(Map<String, Object> params) {
        System.out.println("select ---selectInterestsList class");
        return interestMapper.selectInterestsListV3(params);
    }

這上面的兩個方法就是spring配置文件裏配置的兩個緩存,我這裏主要是對查詢的分頁作緩存。 上面的方法只是添加緩存,並10分鐘後過時。這裏的key是在redis所對應的標識,若是要查詢出來可使用key值來查詢。框架

若是你須要對緩存進行修改和刪除,這須要使用@CachePut@CacheEvict 。使用方法以下less

Cache註解詳解

- @CacheConfig:主要用於配置該類中會用到的一些共用的緩存配置。在這裏@CacheConfig(cacheNames = "users"):配置了該數據訪問對象中返回的內容將存儲於名爲users的緩存對象中,咱們也能夠不使用該註解,直接經過@Cacheable本身配置緩存集的名字來定義。

- @Cacheable:配置了findByName函數的返回值將被加入緩存。同時在查詢時,會先從緩存中獲取,若不存在纔再發起對數據庫的訪問。該註解主要有下面幾個參數:

    - value、cacheNames:兩個等同的參數(cacheNames爲Spring 4新增,做爲value的別名),用於指定緩存存儲的集合名。因爲Spring 4中新增了@CacheConfig,所以在Spring 3中本來必須有的value屬性,也成爲非必需項了
    - key:緩存對象存儲在Map集合中的key值,非必需,缺省按照函數的全部參數組合做爲key值,若本身配置需使用SpEL表達式,好比:@Cacheable(key = "#p0"):使用函數第一個參數做爲緩存的key值,更多關於SpEL表達式的詳細內容可參考官方文檔

    - condition:緩存對象的條件,非必需,也需使用SpEL表達式,只有知足表達式條件的內容纔會被緩存,好比:@Cacheable(key = "#p0", condition = "#p0.length() < 3"),表示只有當第一個參數的長度小於3的時候纔會被緩存,若作此配置上面的AAA用戶就不會被緩存,讀者可自行實驗嘗試。
    - unless:另一個緩存條件參數,非必需,需使用SpEL表達式。它不一樣於condition參數的地方在於它的判斷時機,該條件是在函數被調用以後才作判斷的,因此它能夠經過對result進行判斷。
    - keyGenerator:用於指定key生成器,非必需。若須要指定一個自定義的key生成器,咱們須要去實現org.springframework.cache.interceptor.KeyGenerator接口,並使用該參數來指定。須要注意的是:該參數與key是互斥的

    - cacheManager:用於指定使用哪一個緩存管理器,非必需。只有當有多個時才須要使用
    - cacheResolver:用於指定使用那個緩存解析器,非必需。需經過org.springframework.cache.interceptor.CacheResolver接口來實現本身的緩存解析器,並用該參數指定。

除了這裏用到的兩個註解以外,還有下面幾個核心註解:

- @CachePut:配置於函數上,可以根據參數定義條件來進行緩存,它與@Cacheable不一樣的是,它每次都會真是調用函數,因此主要用於數據新增和修改操做上。它的參數與@Cacheable相似,具體功能可參考上面對@Cacheable參數的解析
- @CacheEvict:配置於函數上,一般用在刪除方法上,用來從緩存中移除相應數據。除了同@Cacheable同樣的參數以外,它還有下面兩個參數:

    - allEntries:非必需,默認爲false。當爲true時,會移除全部數據
    - beforeInvocation:非必需,默認爲false,會在調用方法以後移除數據。當爲true時,會在調用方法以前移除數據。

5.結束

上面這些就是使用spring cache對redis作緩存的用法。若是在你的項目裏須要能夠試試一番,這裏沒有使用Ecache緩存是由於項目使用分佈式部署,若是是本地緩存就不行了,因此使用redis作緩存,統一存取。

有什麼問題歡迎給我來信或留言!

相關文章
相關標籤/搜索