spring boot 配置ehcache缓存

使用场景

  • 为shiro认证与授权时高频的sql查询配置上缓存
  • shiro有缓存管理器的配置入口,因为做了一些调整,所以要手动配置.

引入

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>

        <dependency>
            <groupId>net.sf.ehcache</groupId>
            <artifactId>ehcache</artifactId>
            <version>2.10.6</version>
        </dependency>

使用

  • 总体上分三步
    1.添加ehcache.xml文件并配置
    2.添加EhCacheConfig类
    3.通过注解使用
- ehcache.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
         updateCheck="false" monitoring="autodetect"
         dynamicConfig="true" >
         
    <diskStore path="java.io.tmpdir/ehcache"/>

    <defaultCache
            maxElementsInMemory="50000"
            eternal="false"
            timeToIdleSeconds="3600"
            timeToLiveSeconds="3600"
            overflowToDisk="true"
            diskPersistent="false"
            diskExpiryThreadIntervalSeconds="120"
    />

    <!-- 认证与授权用的缓存 设置 -->
    <cache name="shiro_cache"
           maxElementsInMemory="50000"
           eternal="true"
           clearOnFlush="false"
           overflowToDisk="true"
           diskSpoolBufferSizeMB="1024"
           maxElementsOnDisk="100000"
           diskPersistent="false"
           diskExpiryThreadIntervalSeconds="120"
           memoryStoreEvictionPolicy="LFU"
           transactionalMode="off">
    </cache>

</ehcache>

    <!--
        maxElementsInMemory="10000"     //Cache中最多允许保存的数据对象的数量
        external="false"                //缓存中对象是否为永久的,如果是,超时设置将被忽略,对象从不过期   
        timeToLiveSeconds="3600"        //缓存的存活时间,从开始创建的时间算起
        timeToIdleSeconds="3600"        //多长时间不访问该缓存,那么ehcache 就会清除该缓存  
        
        1、timeToLiveSeconds的定义是:以创建时间为基准开始计算的超时时长;
        2、timeToIdleSeconds的定义是:在创建时间和最近访问时间中取出离现在最近的时间作为基准计算的超时时长;
        3、如果仅设置了timeToLiveSeconds,则该对象的超时时间=创建时间+timeToLiveSeconds,假设为A;
        4、如果没设置timeToLiveSeconds,则该对象的超时时间=min(创建时间,最近访问时间)+timeToIdleSeconds,假设为B;
        5、如果两者都设置了,则取出A、B最少的值,即min(A,B),表示只要有一个超时成立即算超时。
        
        overflowToDisk="true"           //内存不足时,是否启用磁盘缓存    
        diskSpoolBufferSizeMB   //设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区
        maxElementsOnDisk       //硬盘最大缓存个数
        diskPersistent          //是否缓存虚拟机重启期数据The default value is false    
        diskExpiryThreadIntervalSeconds //磁盘失效线程运行时间间隔,默认是120秒。
        memoryStoreEvictionPolicy="LRU" //当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
        clearOnFlush    //内存数量最大时是否清除
        maxEntriesLocalHeap="0"  //堆内存中最大缓存对象数,0没有限制
        maxEntriesLocalDisk="1000" //硬盘最大缓存个数。
    -->

  • 文件应该放到项目resources目录下,如果调整了位置或者文件名称,需要在配置文件中指定.
  • 可以根据需要增加cache 标签,一个cache 标签可以理解为一个Map.缓存储存时需要指定cache 的名称

EhCacheConfig 类

import net.sf.ehcache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.ehcache.EhCacheCacheManager;
import org.springframework.cache.ehcache.EhCacheManagerFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;

/**
 * ehcache配置
 */
@Configuration
@EnableCaching
public class EhCacheConfig {

    /**
     * EhCache的配置
     */
    @Bean
    public EhCacheCacheManager cacheManager(CacheManager cacheManager) {
        return new EhCacheCacheManager(cacheManager);
    }

    /**
     * EhCache的配置
     */
    @Bean
    public EhCacheManagerFactoryBean ehcache() {
        EhCacheManagerFactoryBean ehCacheManagerFactoryBean = new EhCacheManagerFactoryBean();
        ehCacheManagerFactoryBean.setConfigLocation(new ClassPathResource("ehcache.xml"));
        return ehCacheManagerFactoryBean;
    }
}

  • 主要做的就是创建实例和注入Bean

  • 使用注解前创建几个常量类.非必须
/**
 * 所有缓存名称的集合
 *
 */
public interface CacheName {
    /**
     * 用于进行shiro认证和授权的缓存 应与xml文件一致
     */
    String SHIRO_CACHE = "shiro_cache";
}

/**
 * 缓存标识前缀 

 */
public interface CacheKey {

    /**
     * 用于通过userid获取角色的id和名称集合
     */
    String ROLES_BY_USERID_ = "roles_by_userid_";

    /**
     * 获取用于认证的用户信息
     */
    String USER_AUTH_ = "user_auth_";

}


    @Cacheable(value = CacheName.SHIRO_CACHE ,key = "'" + CacheKey.USER_AUTH_ + "'+#account")
    @Override
    public BaseUser getByAccount(String account){
        return userDao.getByAccount(account);
    }
  • 在通过用户id获取用户角色信息的接口增加注解.
    @Cacheable(value = CacheName.SHIRO_CACHE ,key = "'" + CacheKey.ROLES_BY_USERID_ + "'+#userId")
    List<Map<String,Object>> getRoleIdAndNameByUserId(Long userId);

  • 缓存的删除
  • 缓存的删除一般通过@CacheEvict实现,用于场景的限制,使用了手动删除的方式.
  • 场景:在用户信息变更时,移除认证查询时的缓存,在用户角色信息变更时,移除授权查询的缓存.
    @Autowired
    EhCacheCacheManager ehCacheCacheManager;

   public Long addOrEdit(BaseUser model, RequestPara  para){
        BaseUser user_temp= getByAccount(model.getAccount());
        //如果user_temp不为空,但id一样,说明是进行不改名字的编辑,不视为用户名存在
        Assert.isTrue(user_temp==null||user_temp.getId().equals(model.getId()),"该账号已存在");
        Long id=null;
        if(ModelUtil.isNew(model)){
            if(!StringUtils.hasText(model.getName())){
                model.setName(model.getAccount());
            }
            super.save(model);
        }
        id= model.getId();
        Assert.isTrue(id!=null,"添加用户失败");

        //修改密码
        String is_update_password=WebUtils.get("is_update_password");
        if(YesOrNotEnum.Y.getCodeTest().equals(is_update_password)){
            //密码md5加密后,加盐加密
            String md5Password= null;
            try {
                md5Password = Md5Salt.sec(String.valueOf(id),model.getPassword());
            } catch (Exception e) {
                throw new ServiceException(MsgEnum.ENCRYPT_ERROR);
            }
            model.setPassword(md5Password);
        }

        super.updateById(model);

        //删除shiro_cache内的 用户信息缓存
        CacheManager cacheManager = ehCacheCacheManager.getCacheManager();
        Cache cache = cacheManager.getCache(CacheName.SHIRO_CACHE);
        cache.remove(CacheKey.USER_AUTH_+model.getAccount());


        //设置用户的角色
        String[] role_ids=para.getArray("role_ids");

        if(role_ids!=null){
            Long[] role_ids_int= (Long[]) ConvertUtils.convert(role_ids, Long.class);
            saveRoleInfo(id,role_ids_int);
            //移除角色信息缓存
            cache.remove(CacheKey.ROLES_BY_USERID_+id);
        }

        return model.getId();
    }
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342