广告
返回顶部
首页 > 资讯 > 精选 >SpringBoot整合Ehcache3的实现步骤是什么
  • 516
分享到

SpringBoot整合Ehcache3的实现步骤是什么

2023-06-22 08:06:35 516人浏览 泡泡鱼
摘要

这篇文章主要介绍“SpringBoot整合Ehcache3的实现步骤是什么”,在日常操作中,相信很多人在springBoot整合Ehcache3的实现步骤是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”S

这篇文章主要介绍“SpringBoot整合Ehcache3的实现步骤是什么”,在日常操作中,相信很多人在springBoot整合Ehcache3的实现步骤是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”SpringBoot整合Ehcache3的实现步骤是什么”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

    前言

    公司部门老项目要迁移升级java版本,需要进行缓存相关操作,原框架未支持这部分,经过调研java相关缓存方案大致分为ehcache和redis两种,Redis的value最大值为500mb且超过1mb会对存取有性能影响,业务系统需要支持列表查询缓存就不可避免的涉及到大量的数据存取过滤,ehcache支持内存+磁盘缓存不用担心缓存容量问题,所以框架初步版本决定集成ehcache3,设计流程结构如下图所示

    SpringBoot整合Ehcache3的实现步骤是什么

    缓存配置

    Maven引用

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

    个性化配置

      #缓存配置  cache:    ehcache:      heap: 1000      offheap: 100      disk: 500      diskDir: tempfiles/cache/
    @Component@ConfigurationProperties("frmae.cache.ehcache")public class EhcacheConfiguration {        private int heap;        private int offheap;        private String diskDir;        private int disk;    public EhcacheConfiguration(){        heap = 1000;        offheap = 100;        disk = 500;        diskDir = "tempfiles/cache/";    }}

    代码注入配置

    因为springboot默认缓存优先注入redis配置,所以需要手动声明bean进行注入,同时ehcache的value值必须支持序列化接口,不能使用Object代替,这里声明一个缓存基类,所有缓存value对象必须继承该类

    public class BaseSystemObject implements Serializable {    }
    @Configuration@EnableCachingpublic class EhcacheConfig {    @Autowired    private EhcacheConfiguration ehcacheConfiguration;    @Autowired    private ApplicationContext context;    @Bean(name = "ehCacheManager")    public CacheManager getCacheManager() {        //资源池生成器配置持久化        ResourcePoolsBuilder resourcePoolsBuilder =                   ResourcePoolsBuilder.newResourcePoolsBuilder()                // 堆内缓存大小                .heap(ehcacheConfiguration.getHeap(), EntryUnit.ENTRIES)                // 堆外缓存大小                .offheap(ehcacheConfiguration.getOffheap(), MemoryUnit.MB)                // 文件缓存大小                .disk(ehcacheConfiguration.getDisk(), MemoryUnit.MB);        //生成配置        ExpiryPolicy expiryPolicy = ExpiryPolicyBuilder.noExpiration();        CacheConfiguration config = CacheConfigurationBuilder.newCacheConfigurationBuilder(String.class, BaseSystemObject.class, resourcePoolsBuilder)                //设置永不过期                .withExpiry(expiryPolicy)                .build();        CacheManagerBuilder cacheManagerBuilder = CacheManagerBuilder.newCacheManagerBuilder()                         .with(CacheManagerBuilder.persistence(ehcacheConfiguration.getDiskDir()));        return cacheManagerBuilder.build(true);    }}

    缓存操作

    缓存预热

    针对缓存框架选择的双写策略,即数据库和缓存同时写入,所以在系统启动时需要预先将数据库数据加载到缓存中
    针对单表声明自定义注解,个性化缓存定义自定义接口

    @Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documented@Inheritedpublic @interface HPCache {}
    public interface IHPCacheInitService {    String getCacheName();    void initCache();}

    系统初始化时同步进行缓存初始化,扫描注解实体类与接口实现Bean

    @Async    public void initCache(Class runtimeClass, List<String> extraPackageNameList) {        List<Class<?>> cacheEntityList = new ArrayList<>();        if (!runtimeClass.getPackage().getName().equals(Application.class.getPackage().getName())) {            cacheEntityList.addAll(ScanUtil.getAllClassByPackageName_Annotation(runtimeClass.getPackage(), HPCache.class));        }        for (String packageName : extraPackageNameList) {            cacheEntityList.addAll(ScanUtil.getAllClassByPackageName_Annotation(packageName, HPCache.class));        }        for (Class clazz : cacheEntityList) {            TableName tableName = (TableName) clazz.getAnnotation(TableName.class);            List<LinkedHashMap<String, Object>> resultList = commonDTO.selectList(tableName.value(), "*", "1=1", "", new HashMap<>(), false);            for (LinkedHashMap<String, Object> map : resultList) {                Cache cache = cacheManager.getCache(clazz.getName(), String.class, BaseSystemObject.class);                String unitguid = ConvertOp.convert2String(map.get("UnitGuid"));                try {                    Object obj = clazz.newInstance();                    obj = ConvertOp.convertLinkHashMapToBean(map, obj);                    cache.put(unitguid, obj);                } catch (Exception e) {                    e.printStackTrace();                }            }        }        //自定义缓存        Map<String, IHPCacheInitService> res = context.getBeansOfType(IHPCacheInitService.class);        for (Map.Entry en : res.entrySet()) {            IHPCacheInitService service = (IHPCacheInitService) en.getValue();            service.initCache();        }        System.out.println("缓存初始化完毕");    }

    需要注意,在EhcacheConfig配置类中需要进行缓存名称的提前注册,否则会导致操作缓存时空指针异常

        Map<String, Object> annotatedBeans = context.getBeansWithAnnotation(SpringBootApplication.class);        Class runtimeClass = annotatedBeans.values().toArray()[0].getClass();        //do,dao扫描        List<String> extraPackageNameList = new ArrayList<String>();        extraPackageNameList.add(Application.class.getPackage().getName());        List<Class<?>> cacheEntityList = new ArrayList<>();        if (!runtimeClass.getPackage().getName().equals(Application.class.getPackage().getName())) {            cacheEntityList.addAll(ScanUtil.getAllClassByPackageName_Annotation(runtimeClass.getPackage(), HPCache.class));        }        for (String packageName : extraPackageNameList) {            cacheEntityList.addAll(ScanUtil.getAllClassByPackageName_Annotation(packageName, HPCache.class));        }        for (Class clazz : cacheEntityList) {            cacheManagerBuilder = cacheManagerBuilder.withCache(clazz.getName(), config);        }        //自定义缓存        Map<String, IHPCacheInitService> res = context.getBeansOfType(IHPCacheInitService.class);        for (Map.Entry en :res.entrySet()) {            IHPCacheInitService service = (IHPCacheInitService)en.getValue();            cacheManagerBuilder = cacheManagerBuilder.withCache(service.getCacheName(), config);        }

    更新操作

    手动获取ehcache的bean对象,调用put,repalce,delete方法进行操作

           private  CacheManager cacheManager = (CacheManager) SpringBootBeanUtil.getBean("ehCacheManager");    public void executeUpdateOperation(String cacheName, String key, BaseSystemObject value) {        Cache cache = cacheManager.getCache(cacheName, String.class, BaseSystemObject.class);        if (cache.containsKey(key)) {            cache.replace(key, value);        } else {            cache.put(key, value);        }    }    public void executeDeleteOperation(String cacheName, String key) {        Cache cache = cacheManager.getCache(cacheName, String.class, BaseSystemObject.class);        cache.remove(key);    }

    查询操作

    缓存存储单表以主键&mdash;object形式存储,个性化缓存为key-object形式存储,单条记录可以通过getCache方法查询,列表查询需要取出整个缓存按条件进行过滤

     public Object getCache(String cacheName, String key){        Cache cache = cacheManager.getCache(cacheName, String.class, BaseSystemObject.class);        return cache.get(key);    }    public List<Object> getAllCache(String cacheName){        List result = new ArrayList<>();        Cache cache = cacheManager.getCache(cacheName, String.class, BaseSystemObject.class);        Iterator iter = cache.iterator();        while (iter.hasNext()) {            Cache.Entry entry = (Cache.Entry) iter.next();            result.add(entry.getValue());        }        return result;    }

    缓存与数据库数据一致性

    数据库数据操作与缓存操作顺序为先操作数据后操作缓存,在开启数据库事务的情况下针对单条数据单次操作是没有问题的,如果是组合操作一旦数据库操作发生异常回滚,缓存并没有回滚就会导致数据的不一致,比如执行顺序为dbop1=》cacheop1=》dbop2=》cacheop2,dbop2异常,cacheop1的操作已经更改了缓存
    这里选择的方案是在数据库全部执行完毕后统一操作缓存,这个方案有一个缺点是如果缓存操作发生异常还是会出现上述问题,实际过程中缓存只是对内存的操作异常概率较小,对缓存操作持乐观状态,同时我们提供手动重置缓存的功能,算是一个折中方案,下面概述该方案的一个实现

    声明自定义缓存事务注解

    @Target({ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)@Documented@Inheritedpublic @interface CacheTransactional {}

    声明切面监听,在标记了CacheTransactional注解的方法执行前进行Redis标识,统一执行完方法体后执行缓存操作
    将缓存操作以线程id区分放入待执行队列中序列化到redis,提供方法统一操作

    public class CacheExecuteModel implements Serializable {    private String obejctClazzName;    private String cacheName;    private String key;    private BaseSystemObject value;    private String executeType;}private  CacheManager cacheManager = (CacheManager) SpringBootBeanUtil.getBean("ehCacheManager");    @Autowired    private RedisUtil redisUtil;    public void putCacheIntoTransition(){        String threadID = Thread.currentThread().getName();        System.out.println("init threadid:"+threadID);        CacheExecuteModel cacheExecuteModel = new CacheExecuteModel();        cacheExecuteModel.setExecuteType("option");        redisUtil.redisTemplateSetForCollection(threadID,cacheExecuteModel, GlobalEnum.RedisDBNum.Cache.get_value());        redisUtil.setExpire(threadID,5, TimeUnit.MINUTES, GlobalEnum.RedisDBNum.Cache.get_value());    }    public void putCache(String cacheName, String key, BaseSystemObject value) {        if(checkCacheOptiNIOnInTransition()){            String threadID = Thread.currentThread().getName();            CacheExecuteModel cacheExecuteModel = new CacheExecuteModel("update", cacheName, key, value.getClass().getName(),value);            redisUtil.redisTemplateSetForCollection(threadID,cacheExecuteModel, GlobalEnum.RedisDBNum.Cache.get_value());            redisUtil.setExpire(threadID,5, TimeUnit.MINUTES, GlobalEnum.RedisDBNum.Cache.get_value());        }else{            executeUpdateOperation(cacheName,key,value);        }    }    public void deleteCache(String cacheName, String key) {        if(checkCacheOptinionInTransition()){            String threadID = Thread.currentThread().getName();            CacheExecuteModel cacheExecuteModel = new CacheExecuteModel("delete", cacheName, key);            redisUtil.redisTemplateSetForCollection(threadID,cacheExecuteModel, GlobalEnum.RedisDBNum.Cache.get_value());            redisUtil.setExpire(threadID,5, TimeUnit.MINUTES, GlobalEnum.RedisDBNum.Cache.get_value());        }else{            executeDeleteOperation(cacheName,key);        }    }    public void executeOperation(){        String threadID = Thread.currentThread().getName();        if(checkCacheOptinionInTransition()){            List<LinkedHashMap> executeList =  redisUtil.redisTemplateGetForCollectionAll(threadID, GlobalEnum.RedisDBNum.Cache.get_value());            for (LinkedHashMap obj:executeList) {                String executeType = ConvertOp.convert2String(obj.get("executeType"));                if(executeType.contains("option")){                    continue;                }                String obejctClazzName = ConvertOp.convert2String(obj.get("obejctClazzName"));                String cacheName = ConvertOp.convert2String(obj.get("cacheName"));                String key = ConvertOp.convert2String(obj.get("key"));                LinkedHashMap valueMap = (LinkedHashMap)obj.get("value");                String valueMapJSON =  jsON.toJSONString(valueMap);                try{                    Object valueInstance = JSON.parseObject(valueMapJson,Class.forName(obejctClazzName));                    if(executeType.equals("update")){                        executeUpdateOperation(cacheName,key,(BaseSystemObject)valueInstance);                    }else if(executeType.equals("delete")){                        executeDeleteOperation(cacheName,key);                    }                }catch (Exception e){                    e.printStackTrace();                }            }            redisUtil.redisTemplateRemove(threadID,GlobalEnum.RedisDBNum.Cache.get_value());        }    }    public boolean checkCacheOptinionInTransition(){        String threadID = Thread.currentThread().getName();        System.out.println("check threadid:"+threadID);        return redisUtil.isValid(threadID, GlobalEnum.RedisDBNum.Cache.get_value());    }

    到此,关于“SpringBoot整合Ehcache3的实现步骤是什么”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

    --结束END--

    本文标题: SpringBoot整合Ehcache3的实现步骤是什么

    本文链接: https://www.lsjlt.com/news/303479.html(转载时请注明来源链接)

    有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

    本篇文章演示代码以及资料文档资料下载

    下载Word文档到电脑,方便收藏和打印~

    下载Word文档
    猜你喜欢
    • SpringBoot整合Ehcache3的实现步骤是什么
      这篇文章主要介绍“SpringBoot整合Ehcache3的实现步骤是什么”,在日常操作中,相信很多人在SpringBoot整合Ehcache3的实现步骤是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”S...
      99+
      2023-06-22
    • SpringBoot整合Ehcache3的实现步骤
      目录前言缓存配置maven引用个性化配置代码注入配置缓存操作缓存预热更新操作查询操作缓存与数据库数据一致性前言 公司部门老项目要迁移升级java版本,需要进行缓存相关操作,原框架未支...
      99+
      2022-11-12
    • SpringBoot整合Drools的实现步骤
      目录Drools有什么用 SpringBoot整合Drools初步实战 1.导入Maven依赖2.编写配置类3.resources目录新建rules目录 4.新建实体5.编写规则文件...
      99+
      2022-11-12
    • SpringBoot整合MongoDB的实现步骤
      目录一、技术介绍 1.MongoDB是什么? 二、使用步骤 1.引入maven库 2.具体使用示例 3.配置文件 4.单元测试 总结 一、技术介绍 1.MongoDB是什么? M...
      99+
      2022-11-12
    • SpringBoot 整合mapstruct的实现步骤
      目录前言mapstruct 使用来干什么的?mapstruct 相对于BeanUtils的优势在哪?编码引入依赖创建 DTO、VO运行测试用例怎么解决mapstruct 失效呢?ma...
      99+
      2022-11-12
    • springboot整合mongodb并实现crud步骤详解
      整合 首先我们得使用springboot整合咱们的mongodb,第一步,当然是引入依赖啦 <!--mybatis--> <dependency> ...
      99+
      2022-11-12
    • 详细springboot实现MySQL数据库的整合步骤
      提示:本文适用于初学者,资深玩家仁者见仁智者见智 文章目录 前言一、spring boot的helloworld(1)·有同学可能要问不是链接MySQL吗?不用把MySQL功能也选上吗???(2)此时同学们要问,@GetMap...
      99+
      2023-08-19
      spring boot mysql 数据库
    • SpringBoot整合Minio实现上传文件的完整步骤记录
      目录Minio安装 Minio使用docker安装拉取镜像启动使用9000端口 登录控制台创建存储桶设置桶权限创建 Java 客户端依赖配置文件配置文件配置类创建 minio 客户端...
      99+
      2022-11-13
    • SpringBoot整合RedisTemplate实现缓存信息监控的步骤
      SpringBoot 整合 Redis 数据库实现数据缓存的本质是整合 Redis 数据库,通过对需要“缓存”的数据存入 Redis 数据库中,下次使用时先从...
      99+
      2022-11-13
    • Mybatis_day06:Mybatis整合Spring的步骤是什么
      本篇内容介绍了“Mybatis_day06:Mybatis整合Spring的步骤是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大...
      99+
      2022-10-19
    • Spring整合MyBatis的实现步骤
      目录一、Spring 项目整体目录结构二、Spring 整合 MyBatis 开发环境三、Mapper 接口无实现类开发整合MyBatis 是一款常用的持久层框架,使得程序能够以调用...
      99+
      2023-02-24
      Spring 整合 MyBatis Spring与MyBatis整合
    • SpringBoot整合Freemarker实现页面静态化的详细步骤
      第一步:创建项目添加依赖: <!--web和actuator(图形监控用)基本上都是一起出现的--> <dependency> <groupId...
      99+
      2022-11-13
      SpringBoot整合Freemarker页面静态化 SpringBoot整合Freemarker
    • Spring Boot整合JWT的实现步骤
      springboot整合jwt步骤: 1、登录时,验证账号和密码成功后,生成jwt,返回给前端; 2、前端接收后保存,再做其他操作,比如增删改查时,同时将jwt传给后端进行验证,如果...
      99+
      2022-11-12
    • Springboot整合redis实现发布订阅功能介绍步骤
      目录一、redis发布订阅简介二、几个核心概念解释三、适用场景四、与springboot的整合1、导入基础依赖2、配置文件3、自定义RedisSubConfig4、自定义消息监听器5...
      99+
      2022-11-13
    • SpringBoot整合RocketMQ实现消息发送和接收的详细步骤
      我们使用主流的SpringBoot框架整合RocketMQ来讲解,使用方便快捷; 最终项目结构如下: 具体步骤如下: 第一步:新建SpringBoot项目rocketmq-test...
      99+
      2022-11-12
    • SpringBoot自动配置Quartz的实现步骤是什么
      本篇内容介绍了“SpringBoot自动配置Quartz的实现步骤是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1. 依赖信息spri...
      99+
      2023-06-25
    • SpringBoot整合Quartz及异步调用的方法是什么
      这篇文章主要介绍“SpringBoot整合Quartz及异步调用的方法是什么”,在日常操作中,相信很多人在SpringBoot整合Quartz及异步调用的方法是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答...
      99+
      2023-07-05
    • SpringBoot整合aws的方法是什么
      这篇文章主要讲解了“SpringBoot整合aws的方法是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“SpringBoot整合aws的方法是什么”吧!引入依赖  &...
      99+
      2023-06-21
    • SpringBoot整合RocketMQ的方法是什么
      这篇文章主要介绍了SpringBoot整合RocketMQ的方法是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇SpringBoot整合RocketMQ的方法是什么文章都会有所收获,下面我们一起来看看吧。1...
      99+
      2023-07-05
    • springboot整合mongodb的方法是什么
      这篇文章主要介绍“springboot整合mongodb的方法是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“springboot整合mongodb的方法是什么”文章能帮助大家解决问题。1.mo...
      99+
      2023-07-05
    软考高级职称资格查询
    编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
    • 官方手机版

    • 微信公众号

    • 商务合作