redis使用工具類進行保存數據和Ehcache註解緩存類實現緩存value

前言

本文主要是key value的形式。
這裏我先說下序列化吧

GenericToStringSerializer:使用Spring轉換服務進行序列化(能夠用來專門轉化存放Double等類型,我下面的工具類有介紹);
java

JacksonJsonRedisSerializer:使用Jackson 1,將對象序列化爲JSON;git

Jackson2JsonRedisSerializer:使用Jackson 2,將對象序列化爲JSON;github

JdkSerializationRedisSerializer:使用Java序列化;web

StringRedisSerializer:序列化String類型的key和value。其實是String和byte數組之間的轉換,那麼Key只能是String類型的,不能爲Long,Integer,不然會報錯拋異常。redis

StringSerializer就是經過String.getBytes()來實現的,並且在Redis中,全部存儲的值都是字符串類型的。因此這種方法保存後,經過Redis-cli控制檯,是能夠清楚的查看到咱們保存了什麼key,value是什麼。它只能對String類型進行序列化spring

JdkSerializationRedisSerializer,這個序列化方法是Idk提供的,要求要被序列化的類繼承自Serializeable接口,而後經過Jdk對象序列化的方法保存,這個序列化保存的對象,即便是個String類型的,在redis控制檯,也是看不出來的,仍是相似於 亂碼的東西。由於它保存了一些對象的類型什麼的額外信息。除非中間再加上一些objectmappr就能夠看到內容了,以下數據庫

@Bean
public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) {
    RedisTemplate<String, String> redisTemplate = new RedisTemplate<String, String>();
    redisTemplate.setConnectionFactory(factory);

    //key序列化方式,StringXX是轉爲String,JacksonXX是將對象轉爲json。
    // 須要注意這裏Key使用了StringRedisSerializer,那麼Key只能是String類型的,不能爲Long,Integer,不然會報錯拋異常。
    // 就是假如PostRepository裏定義的@Cacheable(key="0")的話就會報錯,由於這樣做爲key的是int型,key必須爲String。
    //因此在沒有本身定義key生成策略的時候,能夠不配置,我就沒有配置
    RedisSerializer<String> redisSerializer = new StringRedisSerializer();//Long類型不能夠會出現異常信息;
    redisTemplate.setKeySerializer(redisSerializer);

    Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
    ObjectMapper om = new ObjectMapper();
    om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
    om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
    jackson2JsonRedisSerializer.setObjectMapper(om);

    redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);


    return redisTemplate;
}

WX20180320-193953@2x

Ehcache和redis應該怎麼用

我公司的項目中既有Ehcache 又有Redis,因此這裏都會講解
ehcache直接在jvm虛擬機中緩存,速度快,效率高;可是緩存共享麻煩,集羣分佈式應用不方便。express

redis是經過socket訪問到緩存服務,效率比ecache低,比數據庫要快不少,處理集羣和分佈式緩存方便,有成熟的方案。json

若是是單個應用或者對緩存訪問要求很高的應用,用ehcache。
若是是大型系統,存在緩存共享、分佈式部署、緩存內容很大的,建議用redis。數組

補充下:ehcache也有緩存共享方案,不過是經過RMI或者Jgroup多播方式進行廣播緩存通知更新,緩存共享複雜,維護不方便;簡單的共享能夠,可是涉及到緩存恢復,大數據緩存,則不合適

一、springBoot引入spring配置文件,進行redis的搭建

@ImportResource(value = "classpath:applicationContext.xml")
@SpringBootApplication
public class SinoredisSpringbootApplication {

    public static void main(String[] args) {
        SpringApplication.run(SinoredisSpringbootApplication.class, args);
    }
}

1.一、spring配置文件以下

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <description>spring configuration</description>


    <import resource="applicationContext-redis.xml"/>

</beans>

1.二、redis配置信息在properties中以下

########################################################
###REDIS (RedisProperties) redis ######################################################## hlj.redis.host-name=127.0.0.1 hlj.redis.password= hlj.redis.max-total=64 hlj.redis.max-idle=30 hlj.redis.port=6379 hlj.redis.pool.max-wait=-1 

1.三、redis配置文件以下

這裏能夠看到我使用了自定義的key 和value的序列化方式

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig" >
        <property name="maxTotal" value="${hlj.redis.max-total}"/>
        <property name="maxIdle" value="${hlj.redis.max-idle}"/>
        <property name="maxWaitMillis" value="${hlj.redis.pool.max-wait}"/>
    </bean>

    <bean id="jedisFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" destroy-method="destroy">
        <property name="password" value="${hlj.redis.password}"/>
        <property name="hostName" value="${hlj.redis.host-name}"/>
        <property name="port" value="${hlj.redis.port}"/>
        <property name="usePool" value="true"/>
        <property name="poolConfig" ref="jedisPoolConfig"/>
    </bean>

    <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate" scope="prototype">
        <property name="connectionFactory" ref="jedisFactory"/>
        <property name="keySerializer">
            <bean class="com.hlj.redis.cache.CustomStringRedisSerializer"/>
        </property>
        <property name="valueSerializer">
            <bean class="com.hlj.redis.cache.CustomJSONStringRedisSerializer"/>
        </property>
    </bean>
</beans>

1.3.1 自定義key的序列化方式

package com.hlj.config.serializer;

import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.util.Assert;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.nio.charset.Charset;

/** * 類名稱:CustomStringRedisSerializer * 類描述:定製String 序列轉換 * 建立人:qingxu * 修改人: * 修改時間:2016/3/2 15:04 * 修改備註: * * @version 1.0.0 */
public class CustomStringRedisSerializer implements RedisSerializer<Object> {

    private final Charset charset;

    public CustomStringRedisSerializer() {
        this(Charset.forName("UTF8"));
    }

    public CustomStringRedisSerializer(Charset charset) {
        Assert.notNull(charset);
        this.charset = charset;
    }

    public String deserialize(byte[] bytes) {
        return bytes == null?null:new String(bytes, this.charset);
    }

    public byte[] serialize(Object string) {
        if(string == null ) {
            return null;
        }
        if(string instanceof Long){
            return String.valueOf(string).getBytes(this.charset);

        }
        if(string instanceof Integer){
            return String.valueOf(string).getBytes(this.charset);

        }
        if(string instanceof BigDecimal){
            return ((BigDecimal)string).toString().getBytes(this.charset);
        }

        if(string instanceof BigInteger){
            return ((BigInteger)string).toString().getBytes(this.charset);
        }

        if(string instanceof Double){
            return ((Double)string).toString().getBytes(this.charset);
        }

        if(string instanceof Float){
            return ((Float)string).toString().getBytes(this.charset);
        }
        return ((String)string).getBytes(this.charset);
    }
}

1.3.二、自定義value的序列化方式

package com.hlj.config.serializer;

import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

/** * 類名稱:CustomJSONStringRedisSerializer * 類描述:轉換對象爲json字符串 * 建立人:qingxu * 修改人: * 修改時間:2016/3/2 15:04 * 修改備註: * * @version 1.0.0 */
public class CustomJSONStringRedisSerializer implements RedisSerializer<Object> {

    public static final String EMPTY_JSON = "{}";

    public static final byte[] EMPTY_ARRAY = new byte[0];

    private final ObjectMapper mapper;

    /** * Creates {@link CustomJSONStringRedisSerializer} and configures {@link ObjectMapper} for default typing. */
    public CustomJSONStringRedisSerializer() {
        this((String) null);
    }

    /** * Creates {@link CustomJSONStringRedisSerializer} and configures {@link ObjectMapper} for default typing using the * given {@literal name}. In case of an {@literal empty} or {@literal null} String the default * {@link JsonTypeInfo.Id#CLASS} will be used. * * @param classPropertyTypeName Name of the JSON property holding type information. Can be {@literal null}. */
    public CustomJSONStringRedisSerializer(String classPropertyTypeName) {

        this(new RedisObjectMapper());

        if (StringUtils.hasText(classPropertyTypeName)) {
            mapper.enableDefaultTypingAsProperty(ObjectMapper.DefaultTyping.NON_FINAL, classPropertyTypeName);
        } else {
            mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
        }
    }

    /** * Setting a custom-configured {@link ObjectMapper} is one way to take further control of the JSON serialization * process. For example, an extended {@link} can be configured that provides custom serializers for * specific types. * * @param mapper must not be {@literal null}. */
    public CustomJSONStringRedisSerializer(ObjectMapper mapper) {
        Assert.notNull(mapper, "ObjectMapper must not be null!");

        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,false);
        this.mapper = mapper;
    }

    /* * (non-Javadoc) * @see org.springframework.data.redis.serializer.RedisSerializer#serialize(java.lang.Object) */
    @Override
    public byte[] serialize(Object source) throws SerializationException {
        if (source == null) {
            return EMPTY_ARRAY;
        }

        try {
            return mapper.writeValueAsBytes(source);
        } catch (JsonProcessingException e) {
            throw new SerializationException("Could not write JSON: " + e.getMessage(), e);
        }
    }

    /* * (non-Javadoc) * @see org.springframework.data.redis.serializer.RedisSerializer#deserialize(byte[]) */
    @Override
    public Object deserialize(byte[] source) throws SerializationException {
        return deserialize(source, Object.class);
    }

    /** * @param source can be {@literal null}. * @param type must not be {@literal null}. * @return {@literal null} for empty source. * @throws SerializationException */
    public <T> T deserialize(byte[] source, Class<T> type) throws SerializationException {

        Assert.notNull(type,
                "Deserialization type must not be null! Pleaes provide Object.class to make use of Jackson2 default typing.");

        if (source == null || source.length == 0) {
            return null;
        }

        try {
            return mapper.readValue(source, type);
        } catch (Exception ex) {
            throw new SerializationException("Could not read JSON: " + ex.getMessage(), ex);
        }
    }
}

1.3.四、若是使用上面序列化的話,那麼redis庫總能夠看到是class或者是請他的java數據類型,下圖是後期的答案,這裏只是簡單的介紹

WX20180320-194420@2x

WX20180320-194333@2x

1.四、至此,其實redis就已經搭建好了

二、、reids存儲對象工具類

2.一、工具類

一、這個工具類,在描述的時候,就說道,分不清Long和Integer,Double和Float。因此咱們通常只用來存放對象

二、本類中能夠看到有兩個服務類ValueOperationsRedisOperations,可是實際上是同一個類只不過名字不一樣。只是其做用的範圍表面上意思不同,第一個是用來存取數據,第二個用來操做參數數據的

package com.hlj.redis.redisTool;

import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/** * 類描述: * 操做redis 對象數據的工具類 * 提供存取數字外對象的存取,數字類型使用RedisLongData/RedisIntegerData進行操做 * 這個類分不清Long和Integer,Float和Double。也沒法進行原子操做 * 建立人: j.sh * 建立時間: 2016/3/1 * version:1.0.0 */
@Component
public class RedisObjectData {

    @Resource(name="redisTemplate")
    private ValueOperations<String, Object> valueOperations;

    @Resource(name = "redisTemplate")
    private RedisOperations<String,Object> operations;

    /** * 根據key獲取數據 * @param key * @return */
    public Object getData(String key) {
        return valueOperations.get(key);
    }

    /** * 設置數據 * @param key * @param object */
    public void setData(String key,Object object) {
        valueOperations.set(key,object);
    }

    /** * 根據key 刪除對應的數據 * @param key */
    public void delete(String key) {
        operations.delete(key);
    }
}

2.二、controller測試

2.2.一、添加緩存對象和讀取緩存對象

package com.hlj.controller;

import com.hlj.Format.ResponseBean;
import com.hlj.bean.Person;
import com.hlj.redis.redisTool.RedisLongData;
import com.hlj.redis.redisTool.RedisObjectData;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.ArrayList;
import java.util.List;


@Controller
public class RedisObjectDataController {

    @Autowired
    private RedisObjectData redisObjectData;

    /** * 添加緩存對象 */
    @RequestMapping("/setRedisObjectData")
    public @ResponseBody ResponseBean setRedisObjectData(Long id){
        try {
            Person person = new Person();
            person.setName("HealerJean");
            person.setPwd("123456");
            person.setId(id);
            redisObjectData.setData("person", person);
            return  ResponseBean.buildSuccess();
        }catch (Exception e){
            return ResponseBean.buildFailure(e.getMessage());
        }
    }

    /** * 根據key獲取緩存對象 * @return */
    @RequestMapping("/getRedisObjectData")
    public @ResponseBody ResponseBean getRedisObjectData(String key){
        try {
            Person person = (Person) redisObjectData.getData(key);
            return ResponseBean.buildSuccess(person);
        }catch (Exception e){
            return  ResponseBean.buildFailure(e.getMessage());
        }
    }

服務器啓動:
1.一、瀏覽器打開輸入 http://localhost:8080/setRedisObjectData?id=1

WX20180320-122358@2x

1.二、查看redis中的數據,發現已經有數據了數據了

WX20180320-122446@2x

2.一、對數據進行讀取,瀏覽器中打開http://localhost:8080/getRedisObjectData?key=person

WX20180320-122622@2x

2.二、上述讀取數據成功

2.2.二、 根據key值刪除緩存

/** * 根據key刪除緩存對象 * @return */
@RequestMapping("/delRedisObjectData")
public @ResponseBody ResponseBean delRedisObjectData(String key){
    try {
        redisObjectData.delete(key);
        return ResponseBean.buildSuccess();
    }catch (Exception e){
        return  ResponseBean.buildFailure(e.getMessage());
    }
}

1.一、瀏覽器中打開 http://localhost:8080/delRedisObjectData?key=person

WX20180320-122846@2x

1.二、查看redis庫,刪除成功

WX20180320-122931@2x

2.2.三、存儲List對象集合

/** * 添加List緩存對象 * @param id * @return */
@RequestMapping("/setListRedisObjectData")
public @ResponseBody ResponseBean setListRedisObjectData(Long id){
    try {
        List<Person> persons = new ArrayList<>();
        Person person1= new Person(id,"HealerJean"+id,"password"+id);
        Person person2 = new Person(id+1,"HuangLiang"+id,"HuangLiang"+id);
        persons.add(person1);
        persons.add(person2);
        redisObjectData.setData("persons", persons);
        return  ResponseBean.buildSuccess();
    }catch (Exception e){
        return ResponseBean.buildFailure(e.getMessage());
    }
}

/** * 根據key獲取緩存List對象 * @return */
@RequestMapping("/getListRedisObjectData")
public @ResponseBody ResponseBean getListRedisObjectData(String key){
    try {
        List<Person> persons = (List<Person>) redisObjectData.getData(key);
        return ResponseBean.buildSuccess(persons);
    }catch (Exception e){
        return  ResponseBean.buildFailure(e.getMessage());
    }
}

1.一、瀏覽器中打開http://localhost:8080/setListRedisObjectData?id=1

WX20180320-123152@2x

1.二、查看redis庫,有數據

WX20180320-123233@2x

2.一、根據key值獲取list對象,瀏覽器中打開http://localhost:8080/getListRedisObjectData?key=persons

WX20180320-123356@2x

2.二、成功,下面要測試,清除下redis庫

fulshdb

2.2.四、測試放入Long,報錯誤異常Integer不能轉化爲Long

/** * 添加Long類型緩存對象,這是個錯誤的演示,僅供測試 * @param id * @return */
@RequestMapping("/set")
public @ResponseBody ResponseBean set(Long id){
    try {

        redisObjectData.setData("id", id);
        return  ResponseBean.buildSuccess();
    }catch (Exception e){
        return ResponseBean.buildFailure(e.getMessage());
    }
}

/** * 根據key獲取Long,這是個錯誤的演示,僅供測試 * @return */
@RequestMapping("/get")
public @ResponseBody ResponseBean get(String key){
    try {
        Long id = (Long) redisObjectData.getData("id");
        return ResponseBean.buildSuccess(id);
    }catch (Exception e){
        return  ResponseBean.buildFailure(e.getMessage());
    }
}

1.一、瀏覽器中打開http://localhost:8080/set?id=1

WX20180320-131826@2x

1.二、查看redis庫

WX20180320-131858@2x

2.一、根據key值獲取,這個時候 就會報錯了,朋友們,提示Integer不能轉化爲long

WX20180320-132003@2x

三、redis存取Long類型工具類

3.一、工具類代碼

package com.hlj.redis.redisTool;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.serializer.GenericToStringSerializer;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

/** * 類描述: * redis操做Long類型數據的工具類 * 提供Long類型原子操做 * 默認一天過時,其餘過時時間調用setExpire * 建立人: j.sh * 建立時間: 2016/3/1 * version:1.0.0 */
@Component
public class RedisLongData implements InitializingBean {

    @Resource(name="redisTemplate")
    private ValueOperations<String, Long> valueOperations;

    @Resource(name="redisTemplate")
    private RedisTemplate<String,Long> redisTemplate;


    @Override
    public void afterPropertiesSet() throws Exception {
        redisTemplate.setValueSerializer(new GenericToStringSerializer<Long>(Long.class));
        valueOperations = redisTemplate.opsForValue();
    }

    /** * 根據key 刪除 * @param key */
    public void delete(String key) {
        redisTemplate.delete(key);
    }

    /** * 進行數值的增長 * @param key * @param value * @return */
    public Long increase(String key,long value){
        Long result = valueOperations.increment(key,value);
        this.setExpire(key,1L,TimeUnit.DAYS);
        return result;
    }

    /** * 進行數值的增長 * @param key * @return */
    public Long increase(String key){
        return increase(key,1);
    }

    /** * 進行數值的遞減 * @param key * @param value * @return */
    public Long decrease(String key,long value){
        Long result =  valueOperations.increment(key,0-value);
        this.setExpire(key,1L,TimeUnit.DAYS);
        return result;
    }

    /** * 進行數值的遞減 * @param key * @return */
    public Long decrease(String key){
        return decrease(key,1);
    }

    /** * 根據key獲取 * @param key * @return */
    public Long get(String key) {
        return valueOperations.get(key);
    }

    /** * 設置 * @param key * @param value */
    public void set(String key,Long value) {
        valueOperations.set(key,value);
        this.setExpire(key,1L,TimeUnit.DAYS);
    }

    /** * 過時時間,默認單位秒 * @param key * @param time */
    public void setExpire(String key,Long time){
        redisTemplate.expire(key,time, TimeUnit.SECONDS);
    }

    /** * 過時時間 * @param key * @param time * @param timeUnit */
    public void setExpire(String key,Long time,TimeUnit timeUnit){
        redisTemplate.expire(key,time,timeUnit);
    }

}

3.二、controller測試。沒啥問題。本身測試吧

package com.hlj.controller;

import com.hlj.Format.ResponseBean;
import com.hlj.redis.redisTool.RedisLongData;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class RedisLongDataController {


    @Autowired
    private RedisLongData redisLongData;

    /** * 添加Long類型的緩存數據 */
    @RequestMapping("/setRedisLongData")
    public @ResponseBody  ResponseBean setRedisLongData(Long id){
        try {
            redisLongData.set("long",id);
            return  ResponseBean.buildSuccess();
        }catch (Exception e){
            return ResponseBean.buildFailure(e.getMessage());
        }
    }

    /** * 獲取Long類型的緩存數據 */

    @RequestMapping("/getRedisLongData")
    public @ResponseBody ResponseBean getRedisLongData(String key){
        try {
            Long id = redisLongData.get(key);
            return ResponseBean.buildSuccess(id);
        }catch (Exception e){
            return  ResponseBean.buildFailure(e.getMessage());
        }
    }

}

四、Ehcache

那麼關於它的使用,我先說明,這裏是要使用註解的,並且是很是完美的註解

一、依賴的導入

<!-- 包含支持UI模版(Velocity,FreeMarker,JasperReports), 郵件服務, 腳本服務(JRuby), 緩存Cache(EHCache), 任務計劃Scheduling(uartz)。 -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context-support</artifactId>
</dependency>
<!-- 集成ehcache須要的依賴-->
<dependency>
    <groupId>net.sf.ehcache</groupId>
    <artifactId>ehcache</artifactId>
</dependency>

二、緩存配置文件

以前學習的時候,這個配置文件中藥寫入value的緩存策略,可是我作了一個自定義的緩存管理器,直接在Java類中配置常量就能夠了,很是小巧和方便

<!--
  ~ Hibernate, Relational Persistence for Idiomatic Java
  ~
  ~ Copyright (c) 2007, Red Hat Middleware LLC or third-party contributors as
  ~ indicated by the @author tags or express copyright attribution
  ~ statements applied by the authors. All third-party contributions are
  ~ distributed under license by Red Hat Middleware LLC.
  ~
  ~ This copyrighted material is made available to anyone wishing to use, modify,
  ~ copy, or redistribute it subject to the terms and conditions of the GNU
  ~ Lesser General Public License, as published by the Free Software Foundation.
  ~
  ~ This program is distributed in the hope that it will be useful,
  ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  ~ or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
  ~ for more details.
  ~
  ~ You should have received a copy of the GNU Lesser General Public License
  ~ along with this distribution; if not, write to:
  ~ Free Software Foundation, Inc.
  ~ 51 Franklin Street, Fifth Floor
  ~ Boston, MA  02110-1301  USA
  -->
<ehcache updateCheck="false">

    <!-- Sets the path to the directory where cache .data files are created.

         If the path is a Java System Property it is replaced by
         its value in the running VM.

         The following properties are translated:
         user.home - User's home directory
         user.dir - User's current working directory
         java.io.tmpdir - Default temp file path -->
    <!--<diskStore path="c:\dev\cache"/>-->

    <!--
       name:Cache的惟一標識
       maxElementsInMemory:內存中最大緩存對象數
       maxElementsOnDisk:磁盤中最大緩存對象數,如果0表示無窮大
       eternal:Element是否永久有效,一但設置了,timeout將不起做用
       overflowToDisk:配置此屬性,當內存中Element數量達到maxElementsInMemory時,Ehcache將會Element寫到磁盤中
       timeToIdleSeconds:設置Element在失效前的容許閒置時間。僅當element不是永久有效時使用,可選屬性,默認值是0,也就是可閒置時間無窮大
       timeToLiveSeconds:設置Element在失效前容許存活時間。最大時間介於建立時間和失效時間之間。僅當element不是永久有效時使用,默認是0.,也就是element存活時間無窮大
       diskPersistent:是否緩存虛擬機重啓期數據
       diskExpiryThreadIntervalSeconds:磁盤失效線程運行時間間隔,默認是120秒
       diskSpoolBufferSizeMB:這個參數設置DiskStore(磁盤緩存)的緩存區大小。默認是30MB。每一個Cache都應該有本身的一個緩衝區
       memoryStoreEvictionPolicy:當達到maxElementsInMemory限制時,Ehcache將會根據指定的策略去清理內存。默認策略是LRU(最近最少使用)。你能夠設置爲FIFO(先進先出)或是LFU(較少使用)
       -->

    <defaultCache
            maxElementsInMemory="10000"
            eternal="false"
            timeToIdleSeconds="600"
            timeToLiveSeconds="600"
            overflowToDisk="true"
            maxElementsOnDisk="10000000"
            diskPersistent="false"
            diskExpiryThreadIntervalSeconds="120"
            diskSpoolBufferSizeMB="64"
            memoryStoreEvictionPolicy="LRU"
    />
    <!--中間能夠包含其餘的緩存key-->

</ehcache>

三、spring中進行配置

<?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:cache="http://www.springframework.org/schema/cache" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd " >


    <description>spring configuration</description>


    <import resource="applicationContext-redis.xml"/>


    <!-- 自定義Ehcache緩存,根據java類加入更多的key 支持註解緩存 -->
    <cache:annotation-driven/>

    <bean id="cacheManager" class="com.hlj.Ehcache.config.CustomEhCacheManager">
        <property name="cacheManager" ref="ehcacheManager"/>
    </bean>

    <bean id="ehcacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
        <property name="configLocation" value="classpath:ehcache.xml"/>
        <property name="shared" value="true"/>
    </bean>

</beans>

3.一、配置自定義的緩存管理器

package com.hlj.Ehcache.config;

import net.sf.ehcache.Ehcache;
import net.sf.ehcache.config.CacheConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.Cache;
import org.springframework.cache.ehcache.EhCacheCache;
import org.springframework.cache.ehcache.EhCacheCacheManager;

import java.lang.reflect.Field;
import java.util.*;

/** * 類描述:繼承 EhCacheCacheManager * @Description 初始化緩存。加載@CacheConstants中緩存定義及緩存自定義過時時間 * @Date 2018/3/21 下午2:46. */
public class CustomEhCacheManager extends EhCacheCacheManager {

    private static String CACHE_PREFIX = "CACHE_";
    private static String EXPIRE_PREFIX = "EXPIRE_";
    private static Logger logger = LoggerFactory.getLogger(CustomEhCacheManager.class);

    private static List<String> cacheNames = new ArrayList<>();
    private static Map<String,Long> expires = new HashMap<>();

    @Override
    public void afterPropertiesSet() {
        try {
            Class clazz = CacheConstants.class;
            Field[] fields = clazz.getDeclaredFields();
            for(Field field : fields){
                if (field.getName().startsWith(CACHE_PREFIX)){
                    cacheNames.add(field.get(clazz).toString());
                } else if (field.getName().startsWith(EXPIRE_PREFIX)){
                    expires.put(
                            clazz.getField(field.getName().replace(EXPIRE_PREFIX,"")).get(clazz).toString(),
                            Long.parseLong(field.get(clazz).toString())
                    );
                }
            }
        } catch (Exception e) {
            logger.error(e.getMessage(),e);
            throw new RuntimeException("init cache failure!",e);
        }
        super.afterPropertiesSet();
    }

    @Override
    protected Collection<Cache> loadCaches() {
        LinkedHashSet<Cache> caches = new LinkedHashSet<Cache>(cacheNames.size());
        for(String name:cacheNames){
            Ehcache exist = this.getCacheManager().addCacheIfAbsent(name);
            if(exist != null){
                Cache cache = new EhCacheCache(exist);
                Ehcache ehcache = (Ehcache) cache.getNativeCache();
                CacheConfiguration configuration = ehcache.getCacheConfiguration();
                Long time = expires.get(name);
                configuration.setTimeToIdleSeconds(time);
                configuration.setTimeToLiveSeconds(time);
                caches.add(cache);
            }
        }
        return caches;
    }
}

3.二、字段以緩存策略的名稱,也叫緩存位置名稱

package com.hlj.Ehcache.config;

/** * 類名稱:CacheConstants * 類描述:緩存常量類 * 建立人:HealerJean * 須要初始化的緩存定義名稱須要以CACHE_爲前綴。如:CACHE_XXX * 若是須要增長自定義過時時間,則增長過時時間變量定義EXPIRE_爲前綴的緩存過時時間.如:EXPIRE_CACHE_XXX * 如不設置自定義過時時間即默認spring cache中設置過時時間 * * @version 1.0.0 */
public class CacheConstants {

    //公共緩存,1分鐘過時時間
    public static final String CACHE_PUBLIC_PERSON = "cache.public.person";
    public static final Long EXPIRE_CACHE_PUBLIC_PERSON = 60L;


    public static final String CACHE_PUBLIC = "cache.public";
    public static final Long EXPIRE_CACHE_PUBLIC = 60L;

    public static final String CACHE_PUBLIC_TEN_MINUTE = "cache.public.ten.minute";
    public static final Long EXPIRE_CACHE_PUBLIC_TEN_MINUTE = 10 * 60L;

}

四、開始測試吧,朋友們,這裏不像多講解了,主要仍是看代碼吧,註釋也很是詳細

一、controller

package com.hlj.Ehcache.controller;


import com.hlj.Ehcache.service.EhcacheService;
import com.hlj.bean.Person;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.List;

/** * @Description * @Author HealerJean * @Date 2018/3/21 下午1:58. */
@Controller
public class EhCacheController {


    @Autowired
    private EhcacheService ehcacheService;

    @GetMapping("save")
    public @ResponseBody Person save(Long id) {
        Person person = new Person(id,"EhcacheHealerJean","123465");
        return ehcacheService.save(person);
    }

    @GetMapping("findById")
    public @ResponseBody Person findById(Long id) {
        return ehcacheService.findById(id);
    }

    @GetMapping("update")
    public @ResponseBody Person update(Person person) {
        return ehcacheService.update(person);
    }

    @GetMapping("delete")
    public @ResponseBody String delete(Long id) {
        ehcacheService.delete(id);
        return "刪除成功";
    }

    @GetMapping("listPerson")
    public@ResponseBody  List<Person> listPerson() {
        return ehcacheService.listPerson();
    }
}

4.二、service

package com.hlj.Ehcache.service.impl;

import com.hlj.Ehcache.config.CacheConstants;
import com.hlj.Ehcache.service.EhcacheService;
import com.hlj.bean.Person;
import com.hlj.repository.PersonRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.util.List;

/** * @Description * @Author HealerJean * @Date 2018/3/21 下午1:59. */
@Service
public class EhcacheServiceImpl implements EhcacheService{

    @Autowired
    private PersonRepository personRepository;


    //這裏的單引號不能少,不然會報錯,被識別是一個對象;
    public static final String CACHE_KEY = "'person'";

    /** * value屬性表示使用哪一個緩存策略,緩存策略在ehcache.xml,如今存放在下面的實體類中,在啓動的時候自動加載了 * 也叫緩存存放位置名稱,不能爲空 */
    public static final String DEMO_CACHE_NAME = CacheConstants.CACHE_PUBLIC_PERSON;


    /** * 保存數據,防止是更新的操做,因此將以前緩存的刪除,事實上,我也並無很成功的實現它,後來明白啦,哈,原來是list集合緩存的時候,添加要刪除的哦 * @param Person */

    @CacheEvict(value=DEMO_CACHE_NAME,key=CACHE_KEY)
    public Person save(Person Person){
        return personRepository.save(Person);
    }

    /** * 查詢數據. * @param id * @return */
    @Cacheable(value=DEMO_CACHE_NAME ,key="'Person_'+#id")
    public Person findById(Long id){
        return personRepository.findOne(id);
    }

    /** * 修改數據. * 在支持Spring Cache的環境下,與@Cacheable不一樣的是使用@CachePut標註的方法在執行前不會去檢查緩存中是否存在以前執行過的結果,而是每次都會執行該方法,並將執行結果以鍵值對的形式存入指定的緩存中。  @CachePut也能夠標註在類上和方法上。使用@CachePut時咱們能夠指定的屬性跟@Cacheable是同樣的。 */
    @CachePut(value = DEMO_CACHE_NAME,key = "'Person_'+#person.getId()")
    public Person update(Person person)  {
        Person Person = personRepository.findOne(person.getId());
        Person.setName(person.getName());
        Person.setPwd(person.getPwd());
        return Person;
    }


    /** * 刪除數據. * @param id */
    @CacheEvict(value = DEMO_CACHE_NAME,key = "'Person_'+#id")//這是清除緩存.
    public void delete(Long id){
        personRepository.delete(id);
    }

    @Cacheable(value=DEMO_CACHE_NAME ,key=CACHE_KEY)
    public List<Person> listPerson() {
        return personRepository.findAll();
    }
}

代碼下載





若是滿意,請打賞博主任意金額,感興趣的請下方留言吧。可與博主自由討論哦

支付包 微信 微信公衆號
支付寶 微信 微信公衆號
相關文章
相關標籤/搜索