精华内容
下载资源
问答
  • springboot整合ehcache
    2022-03-10 17:12:05

    1.在resources目录下添加ehcache的配置文件ehcache.xml

    <ehcache>
        <diskStore path="java.io.tmpdir/shiro-spring-sample"/>
        <defaultCache
                maxElementsInMemory="10000"
                eternal="false"
                timeToIdleSeconds="120"<!--设置对象在失效前的允许时间(:秒)当	
    eternal=false的时候对象不是永久有效时使用,可选属性,默认值是0,也就是闲置时间无限大-->
                timeToLiveSeconds="120"<!--设置对象在失效前允许存活时间(单位:秒)。最
    	大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大-->
                overflowToDisk="false"<!--当内存中对象数量达到maxElementsInMemory时
    	Ehcache将会对象写到磁盘中-->
                diskPersistent="false"<!--是否缓存虚拟机重启期数据->
                diskExpiryThreadIntervalSeconds="120"
        />
        <cache name="user" <!--缓存名字-->
                maxElementsInMemory="10000"<!--缓存最大数--> 
                eternal="true"<!--对象是否永久有效,一旦设置timeout将不起作用--> 
                overflowToDisk="true"<!--缓存最大数--> 
                diskPersistent="true"<!--缓存最大数--> 
                diskExpiryThreadIntervalSeconds="600"/><!--缓存最大数--> 
    </ehcache>

    配置含义

    1. diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
    2. maxElementsOnDisk:硬盘最大缓存个数。

    注解 @EnableCaching// 标注启动了缓存

    @Bean:向spring容器中加入bean

    value:缓存位置名称,不能为空,如果使用EHCache,就是ehcache.xml中声明的cache的name

        key:缓存的key,默认为空,既表示使用方法的参数类型及参数值作为key,支持SpEL

        condition:触发条件,只有满足条件的情况才会加入缓存,默认为空,既表示全部都加入缓存,支持SpEL

        allEntries:CacheEvict参数,true表示清除value中的全部缓存,默认为false

    更多相关内容
  • EhCache是一个纯Java的进程内缓存框架,具有快速、精干等特点,是Hibernate中默认的CacheProvider。这篇文章给大家介绍了springboot整合EHCache的实践方案,需要的朋友参考下
  • 主要介绍了详解springboot整合ehcache实现缓存机制,ehcache提供了多种缓存策略,主要分为内存和磁盘两级,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
  • SpringBoot整合EhCache

    2022-05-14 14:52:44
    -- EhCache依赖 --> <dependency> <groupId>net.sf.ehcache</groupId> <artifactId>ehcache</artifactId> <version>2.10.6</version> </dependency> <...

    一、引入依赖

    <!-- EhCache依赖 -->
    <dependency>
        <groupId>net.sf.ehcache</groupId>
        <artifactId>ehcache</artifactId>
        <version>2.10.6</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-cache</artifactId>
    </dependency>
    
    

    二、开启缓存

    //启动类添加该注解
    @EnableCaching// 标注启动了缓存
    

    三、配置文件: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">
        <!--
           diskStore:为缓存路径,ehcache分为内存和磁盘两级,此属性定义磁盘的缓存位置。参数解释如下:
           user.home – 用户主目录
           user.dir  – 用户当前工作目录
           java.io.tmpdir – 默认临时文件路径
         -->
        <diskStore path="java.io.tmpdir/Tmp_EhCache"/>
        <!--
           defaultCache:默认缓存策略,当ehcache找不到定义的缓存时,则使用这个缓存策略。只能定义一个。
         -->
        <!--
          name:缓存名称。
          maxElementsInMemory:缓存最大数目
          maxElementsOnDisk:硬盘最大缓存个数。
          eternal:对象是否永久有效,一但设置了,timeout将不起作用。
          overflowToDisk:是否保存到磁盘,当系统当机时
          timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
          timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。
          diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
          diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
          diskExpirTyhreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
          memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
          clearOnFlush:内存数量最大时是否清除。
          memoryStoreEvictionPolicy:可选策略有:LRU(最近最少使用,默认策略)、FIFO(先进先出)、LFU(最少访问次数)。
          FIFO,first in first out,这个是大家最熟的,先进先出。
          LFU, Less Frequently Used,就是上面例子中使用的策略,直白一点就是讲一直以来最少被使用的。如上面所讲,缓存的元素有一个hit属性,hit值最小的将会被清出缓存。
          LRU,Least Recently Used,最近最少使用的,缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。
       -->
    <!--    <defaultCache
                eternal="false"
                maxElementsInMemory="10000"
                overflowToDisk="false"
                diskPersistent="false"
                timeToIdleSeconds="120"
                timeToLiveSeconds="120"
                memoryStoreEvictionPolicy="LRU"/>-->
    
        <cache
                name="user"
                eternal="false"
                maxElementsInMemory="10000"
                overflowToDisk="false"
                diskPersistent="false"
                timeToIdleSeconds="600"
                timeToLiveSeconds="600"
                memoryStoreEvictionPolicy="LRU"/>
    
    </ehcache>
    

    四、yml配置

    指定了 EhCache 的配置文件位置
    spring:
      cache:
        type: ehcache
        ehcache:
          config: classpath:/ehcache.xml 
    

    五、开始使用

    1、@CacheConfig

    这个注解在类上使用,用来描述该类中所有方法使用的缓存名称,
    当然也可以不使用该注解,直接在具体的缓存注解上配置名称,示例代码如下:

    @Service
    @CacheConfig(cacheNames = "user")
    public class UserServiceImpl implements UserService {
    
    }
    
    
    2、@Cacheable

    这个注解一般加在查询方法上,表示将一个方法的返回值缓存起来,默认情况下,缓存的 key 就是方法的参数,缓存的 value 就是方法的返回值。示例代码如下:

    @Override
    @Cacheable(value = "user", key = "#id")
    public User getUserById(Long id) {
        return userMapper.getUserById(id);
    }
    

    ①:如果在类上没有加入 @CacheConfig,我们则需要使用 value 来指定缓存名称
    ②:这里如果需要多个 key 时,需要使用 “:” 来连接,如:

    @Cacheable(value = "user", key = "#id+':'+#name")
    
    展开全文
  • SpringBoot整合Ehcache3

    2022-01-03 15:20:41
    公司部门老项目要迁移升级java版本,需要进行缓存相关操作,原框架未支持这部分,经过调研java相关缓存方案大致分为ehcache和redis两种,redis的value最大值为500mb且超过1mb会对存取有性能影响,业务系统需要支持...

    前言

    公司部门老项目要迁移升级java版本,需要进行缓存相关操作,原框架未支持这部分,经过调研java相关缓存方案大致分为ehcache和redis两种,redis的value最大值为500mb且超过1mb会对存取有性能影响,业务系统需要支持列表查询缓存就不可避免的涉及到大量的数据存取过滤,ehcache支持内存+磁盘缓存不用担心缓存容量问题,所以框架初步版本决定集成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 {
        /**
         * ehcache heap大小
         * jvm内存中缓存的key数量
         */
        private int heap;
        /**
         * ehcache offheap大小
         * 堆外内存大小, 单位: MB
         */
        private int offheap;
        /**
         * 磁盘持久化目录
         */
        private String diskDir;
        /**
         * ehcache disk
         * 持久化到磁盘的大小, 单位: MB
         * 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
    @EnableCaching
    public 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
    @Inherited
    public @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);
        }
    

    查询操作

    缓存存储单表以主键—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
    @Inherited
    public @interface CacheTransactional {
    
    }
    

    声明切面监听,在标记了CacheTransactional注解的方法执行前进行Redis标识,统一执行完方法体后执行缓存操作

    @Aspect
    @Component
    @Order(value = 101)
    public class CacheExecuteAspect {
        @Autowired
        private CacheExecuteUtil cacheExecuteUtil;
    
    
        /**
         * 切面点 指定注解
         */
        @Pointcut("@annotation(com.haopan.frame.common.annotation.CacheTransactional) " +
                "|| @within(com.haopan.frame.common.annotation.CacheTransactional)")
        public void cacheExecuteAspect() {
    
        }
    
        /**
         * 拦截方法指定为 repeatSubmitAspect
         */
        @Around("cacheExecuteAspect()")
        public Object around(ProceedingJoinPoint point) throws Throwable {
            MethodSignature signature = (MethodSignature) point.getSignature();
            Method method = signature.getMethod();
            CacheTransactional cacheTransactional = method.getAnnotation(CacheTransactional.class);
            if (cacheTransactional != null) {
                cacheExecuteUtil.putCacheIntoTransition();
                   try{
                       Object obj = point.proceed();
                       cacheExecuteUtil.executeOperation();
                       return obj;
                   }catch (Exception e){
                       e.printStackTrace();
                       throw  e;
                   }
            } else {
                return point.proceed();
            }
        }
    }
    

    将缓存操作以线程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());
        }
    
    展开全文
  • 一、Ehcache介绍 EhCache 是一个纯Java的进程内缓存框架,具有快速、精干等特点,是Hibernate中默认CacheProvider。Ehcache是一种广泛使用的开源Java分布式缓存。主要面向通用缓存,Java EE和轻量级容器。它具有内存...

    一、Ehcache介绍

    EhCache 是一个纯Java的进程内缓存框架,具有快速、精干等特点,是Hibernate中默认CacheProvider。Ehcache是一种广泛使用的开源Java分布式缓存。主要面向通用缓存,Java EE和轻量级容器。它具有内存和磁盘存储,缓存加载器,缓存扩展,缓存异常处理程序,一个gzip缓存servlet过滤器,支持REST和SOAP API等特点。

    主要的特性有:

    1. 快速

    2. 简单

    3. 多种缓存策略

    4. 缓存数据有两级:内存和磁盘,因此无需担心容量问题

    5. 缓存数据会在虚拟机重启的过程中写入磁盘

    6. 可以通过RMI、可插入API等方式进行分布式缓存

    7. 具有缓存和缓存管理器的侦听接口

    8. 支持多缓存管理器实例,以及一个实例的多个缓存区域

    9. 提供Hibernate的缓存实现

    二、Spring缓存抽象

    Spring从3.1开始定义了org.springframework.cache.Cache 和 org.springframework.cache.CacheManager 接口来统一不同的缓存技术;

    • Cache接口为缓存的组件规范定义,包含缓存的各种操作集合;

    • Cache接口下spring提供了各种xxxCache的实现,比如EhCacheCache、RedisCache等等

    • 每次调用需要缓存功能的方法时,Spring会检查指定参数的指定目标方法是否已经被调用过;如果有缓存就直接从缓存中获取结果,没有就调用方法并缓存结果后返回给用户。下次调用则直接从缓存中获取。

    1、缓存注解概念

    Cache缓存接口,定义缓存操作。实现有:EhCacheCache、RedisCache等等
    CacheManager缓存管理器,管理各种缓存组件
    @Cacheable主要针对方法配置,能够根据方法的请求参数对其结果进行缓存
    @CacheEvict清空缓存
    @CachePut保证方法被调用,又希望结果被缓存
    @EnableCaching开启基于注解的缓存

    三、SpringBoot 添加 EhCache缓存

    1、pom.xml 添加依赖

    <!--ehcache 缓存-->
    <dependency>
        <groupId>net.sf.ehcache</groupId>
        <artifactId>ehcache</artifactId>
        <version>2.10.2</version>
    </dependency>
    ​
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-cache</artifactId>
    </dependency>

    2、resources目录下创建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">
        <!-- 磁盘缓存位置 -->
        <diskStore path="E:\data"/>
    ​
        <!-- 默认缓存 -->
        <defaultCache
                maxEntriesLocalHeap="10000"
                eternal="false"
                timeToIdleSeconds="120"
                timeToLiveSeconds="120"
                maxEntriesLocalDisk="10000000"
                diskExpiryThreadIntervalSeconds="120"
                memoryStoreEvictionPolicy="LRU">
            <persistence strategy="localTempSwap"/>
        </defaultCache>
        
        <!-- cache 可以设置多个,例如localCache、UserCache和HelloWorldCache -->
        <cache name="localCache"
               eternal="true"
               maxElementsInMemory="100"
               maxElementsOnDisk="1000"
               overflowToDisk="true"
               diskPersistent="true"
               timeToIdleSeconds="0"
               timeToLiveSeconds="0"
               memoryStoreEvictionPolicy="LRU"/>
    ​
        <cache name="UserCache"
               maxElementsInMemory="1000"
               eternal="false"
               timeToIdleSeconds="10"
               timeToLiveSeconds="10"
               overflowToDisk="false"
               memoryStoreEvictionPolicy="LRU"/>
    ​
        <!-- hello world缓存 -->
        <cache name="HelloWorldCache"
               maxElementsInMemory="1000"
               eternal="false"
               timeToIdleSeconds="5"
               timeToLiveSeconds="5"
               overflowToDisk="false"
               memoryStoreEvictionPolicy="LRU"/>
        <!-- memoryStoreEvictionPolicy Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)-->
        <!-- 缓存配置
         name:缓存名称。
         maxElementsInMemory:缓存最大个数。
         eternal:对象是否永久有效,一但设置了,timeout将不起作用。
         timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
         timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。
         overflowToDisk:当内存中对象数量达到maxElementsInMemory时,Ehcache将会对象写到磁盘中。 diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
         maxElementsOnDisk:硬盘最大缓存个数。
         diskPersistent:是否缓存虚拟机重启期数据 Whether the disk
         store persists between restarts of the Virtual Machine. The default value is false.
         diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
         memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
         clearOnFlush:内存数量最大时是否清除。
         -->
    ​
    </ehcache>

    3、创建测试方法测试CacheManager

    @Test
    void cacheManagerTest() {
        // 1. 创建缓存管理器
        CacheManager cacheManager = CacheManager.create(this.getClass().getResourceAsStream("/ehcache.xml"));
    ​
        // 2. 获取ehcache.xml 中定义的 HelloWorldCache 缓存对象
        Cache cache = cacheManager.getCache("HelloWorldCache");
    ​
        // 3. 创建元素
        Element element = new Element("key1", "value1");
    ​
        // 4. 将元素添加到缓存
        cache.put(element);
    ​
        // 5. 获取缓存
        Element value = cache.get("key1");
        System.out.println(value);
        System.out.println(value.getObjectKey());
        System.out.println(value.getObjectValue());
    ​
        // 6. 删除元素
        cache.remove("key1");
        System.out.println(cache.getSize());
    ​
        // 7. 刷新缓存
        cache.flush();
    ​
        // 8. 关闭缓存管理器
        cacheManager.shutdown();
    }

    运行结果如下:

    [ key = key1, value=value1, version=1, hitCount=1, CreationTime = 1630287141405, LastAccessTime = 1630287141406 ]
    key1
    value1
    0

    四、EhCache封装

    1、封装CacheManagerHelper

    package com.example.ehcachedemo.helper;
    ​
    import net.sf.ehcache.Cache;
    import net.sf.ehcache.CacheManager;
    import net.sf.ehcache.Element;
    ​
    /*
     * Ehcache 缓存管理对象单例
     * 磁盘 + 内存
     * */
    public class CacheManagerHelper {
        private final String EHCAHE_PATH = "/ehcache.xml";
        private final String CACHE_NAME = "localCache";
        private CacheManager manager;
        private Cache cache;
    ​
        private CacheManagerHelper() {
            init();
        }
    ​
        private static class SingletonInstance {
            private static final CacheManagerHelper singleton = new CacheManagerHelper();
        }
    ​
        public static CacheManagerHelper getInstance() {
            return SingletonInstance.singleton;
        }
    ​
        /**
         * 每次开始使用缓存对象需要初始化
         */
        public void init() {
            manager = CacheManager.create(this.getClass().getResourceAsStream(EHCAHE_PATH));
            cache = manager.getCache(CACHE_NAME);
        }
    ​
        /**
         * 把key放入缓存中
         */
        public void put(String key, Object value) {
            cache.put(new Element(key, value));
            flush();
        }
    ​
        /**
         * 根据key获取缓存元素
         */
        public Object get(String key) {
            Element element = cache.get(key);
            return element != null ? element.getObjectValue() : null;
        }
    ​
        /**
         * 根据key移除缓存
         */
        public void remove(String key) {
            cache.remove(key);
            flush();
        }
    ​
        /**
         * 构建内存与磁盘的关系
         */
        public void flush() {
            cache.flush();
        }
    ​
        /**
         * 关闭缓存管理器
         */
        public void shutdown() {
            manager.shutdown();
        }
    }

    2、新建User类和UserController测试CacheManagerHelper

    User:

    package com.example.ehcachedemo.bean;
    ​
    public class User {
    ​
        public User() {
    ​
        }
    ​
        public User(String userId, String name, int age) {
            this.userId = userId;
            this.name = name;
            this.age = age;
        }
    ​
        private String userId;
        private String name;
        private int age;
    ​
        //region getter and setter
        public String getUserId() {
            return userId;
        }
    ​
        public void setUserId(String userId) {
            this.userId = userId;
        }
    ​
        public String getName() {
            return name;
        }
    ​
        public void setName(String name) {
            this.name = name;
        }
    ​
        public int getAge() {
            return age;
        }
    ​
        public void setAge(int age) {
            this.age = age;
        }
        //endregion
    ​
        @Override
        public String toString() {
    ​
            return "User{" +
                    "userId='" + userId + '\'' +
                    ", name='" + name + '\'' +
                    ", age=" + this.age +
                    '}';
        }
    }

    UserController

    package com.example.ehcachedemo.controller;
    ​
    import com.example.ehcachedemo.bean.User;
    import com.example.ehcachedemo.helper.CacheManagerHelper;
    import org.springframework.cache.annotation.Cacheable;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    ​
    @RestController
    @RequestMapping(value = "/user")
    public class UserController {
    ​
        /**
         * 通过CacheManagerHelper获取缓存信息
         * @param id 访问id
         * */
        @GetMapping("byId/{id}")
        public String getUserById(@PathVariable String id) {
            String result = (String) CacheManagerHelper.getInstance().get(id);
            if (result == null) {
                User user = new User(id, "张三", (int) (Math.random() * 100));
                result = user.toString();
                CacheManagerHelper.getInstance().put(id, result);
            }
            return result;
        }
    }

    3、封装EhCacheConfiguration类,用于注解方式使用Ehcache

    package com.example.ehcachedemo.configuration;
    ​
    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;
    ​
    @Configuration
    @EnableCaching
    public class EhCacheConfiguration {
        @Bean
        public EhCacheManagerFactoryBean cacheManagerFactoryBean() {
            EhCacheManagerFactoryBean bean = new EhCacheManagerFactoryBean();
            bean.setConfigLocation(new ClassPathResource("ehcache.xml"));
            bean.setShared(true);
            return bean;
        }
    ​
        @Bean
        public EhCacheCacheManager ehCacheCacheManager(EhCacheManagerFactoryBean bean) {
            return new EhCacheCacheManager(bean.getObject());
        }
    }

    Application启动类需要加入  @EnableCaching 

    4、UserController 注解方式使用EhCache

        /**
         * 通过注解方式,如果缓存存在,则从缓存获取数据,否则从方法体获取,并更新到缓存中
         * @param id 访问id
         * */
        @GetMapping("ByIdWithInject/{id}")
        @Cacheable(value = "localCache", key = "#id")
        public String getUserByIdWithInject(@PathVariable String id) {
            User user = new User(id, "张三", (int) (Math.random() * 100));
            return user.toString();
        }

    5、@Cacheable、@CachePut、@CacheEvict的使用

    在Service使用@Cacheable、@CachePut、@CacheEvict

    package com.example.ehcachedemo.service;
    ​
    import com.example.ehcachedemo.bean.User;
    import org.springframework.cache.annotation.CacheEvict;
    import org.springframework.cache.annotation.CachePut;
    import org.springframework.cache.annotation.Cacheable;
    import org.springframework.stereotype.Component;
    import org.springframework.stereotype.Service;
    ​
    import java.util.Date;
    ​
    @Service
    @Component
    public class UserServiceImpl implements UserService {
    ​
        /**
         * @param userId
         * @return
         * @Cacheable: 1.方法运行之前,先去查询Cache(缓存组件),按照cacheNames指定的名字获取;
         * 2.去Cache中查找缓存的内容,使用一个key,默认就是方法的参数;
         * 3.没有查到缓存就调用目标方法
         * 4.将目标方法返回的结果,放进缓存中
         * 5.condition:指定符合条件的情况下才缓存;
         */
        @Cacheable(value = "UserCache", key = "#userId", condition = "#userId!=''")
        @Override
        public User findById(String userId) {
            System.out.println(new Date().getTime() + "进入UserService.findById,当前userId为:" + userId);
            return new User(userId, "张三", (int) (Math.random() * 100));
        }
    ​
        /**
         * @param user
         * @return
         * @CachePut:既调用方法,又更新缓存数据;同步更新缓存 运行时机:
         * 1、先调用目标方法
         * 2、将目标方法的结果缓存起来
         */
        @CachePut(value = "UserCache", key = "#user.userId")
        @Override
        public User updateUser(User user) {
            System.out.println(new Date().getTime() + "进入UserService.updateUser,当前userId为:" + userId);
            return new User(userId, "张三", (int) (Math.random() * 100));
        }
    ​
        /**
         * @param userId
         * @CacheEvict:缓存清除 key:指定要清除的数据
         * beforeInvocation = true:代表清除缓存操作是在方法运行之前执行,无论方法是否出现异常,缓存都清除
         */
        @CacheEvict(value = "UserCache", key = "#userId", beforeInvocation = true)
        @Override
        public void deleteUser(String userId) {
            System.out.println(new Date().getTime() + "进入UserService.deleteUser,当前userId为:" + userId);
        }
    }

    测试代码

        @Autowired
        UserService userService;
    ​
        @Test
        void userTest() throws InterruptedException {
            // 1.新增
            User user1 = new User("123", "张三", (int) (Math.random() * 100));
            userService.updateUser(user1);
            System.out.println("初始:" + user1);
    ​
            // 2.查询
            user1 = userService.findById("123");
            System.out.println("查询:" + user1);
    ​
            // 3.清除
            userService.deleteUser("123");
            System.out.println("已清除缓存");
    ​
            // 4.查询
            user1 = userService.findById("123");
            System.out.println("查询:" + user1);
    ​
            System.out.println("休眠10秒后重新查询");
            Thread.sleep(10 * 1000);  // 休眠10秒,测试是否过期重新获取
            user1 = userService.findById("123");
            System.out.println(user1);
        }

    测试结果

    1630291225178进入UserService.updateUser,当前userId为:123
    初始:User{userId='123', name='张三', age=82}
    查询:User{userId='123', name='张三', age=82}
    1630291225232进入UserService.deleteUser,当前userId为:123
    已清除缓存
    1630291225232进入UserService.findById,当前userId为:123
    查询:User{userId='123', name='张三', age=21}
    休眠10秒后重新查询
    1630291235234进入UserService.findById,当前userId为:123
    User{userId='123', name='张三', age=13}

    展开全文
  • 在线支付系统需要极高的稳定性,在有限的系统资源下,稳定性优先级要高于系统并发以及用户体验,因此需要合理的控制用户的支付请求...下面通过本文给大家介绍springboot整合ehcache 实现支付超时限制的方法,一起看看吧
  • ehcache与redis集成,提供数据拦截器解决缓存穿透问题。同时,二级缓存大大降低了缓存雪崩和击穿的可能性。此外,还提供了redis超时键本地同步删除功能,缓解了redis与本地缓存的数据一致性问题。 开源项目github ...
  • SpringBoot2.7.2版本整合ehcache
  • 最近做了个微信公众号后台,因为只是单应用就选用了ehcache来做本地缓存,主要是用于缓存微信的accece_token和jsapi_ticket。在使用ehcache的时候遇到了@Cacheable注解没有生效的情况。 经查发现问题在于 类实现了...
  • springboot整合redis+ehcache实现二级缓存
  • @Cacheable 作用:把方法的返回值添加到 Ehcache 中做缓存 @Cacheable (value=“xxx”,key="xxxx") Value 属性:指定一个 Ehcache 配置文件中的缓存策略,如果没有给定 value,那么则表示使用默认的缓存策略 ...
  • ehcache的概述 1.@Cacheable注解的作用 @Cacheable 对当前的对象做缓存处理 @Cacheable public List findUserAll() { return this.userRepository.findAll(); } @Cacheable 作用:把方法的返回值添加到 Ehcache ...
  • SpringBoot 整合ehcache 3.x

    千次阅读 2019-09-12 14:05:39
    SpringBoot 整合ehcache 3.x
  • springboot整合ehcache+redis实现双缓存

    千次阅读 2019-06-18 13:53:17
    在一些对并发业务要求较高的场景下,对页面数据的响应是个急需解决的...要么太复杂,要么太简单,最近抽空思考了一下这一思路的简单实现,下面就用springboot整合ehcache和redis来说明一下实现的过程, 需求说明...
  • springboot整合ehcache

    2020-05-27 22:17:35
    引入依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId>...net.sf.ehcache</groupId> <artif
  • 在application.properties文件中加入spring.cache.ehcache.cofig=ehcache.xml spring.datasource.driverClassName=com.mysql.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/ss...
  • 写在前头,以下内容主要是为了自己复习之用,如果...2. 整合mybatis实现数据库操作 2.1 添加mysql和mybatis依赖,版本要正确,我导入mysql8.0时,报错:CLIENT_PLUGIN_AUTH is required,改为mysql 5.1.35正常。同...
  • springboot整合Ehcache

    2019-02-13 17:47:00
     这样,Ehcache已经整合springboot中了。 简单测试缓存: package com.example.demo.dao; import org.springframework.data.jpa.repository.JpaRepository; import com.example.demo.entity.Student; ...
  • springboot整合ehcache的两种方法

    千次阅读 2020-02-27 23:48:01
    1、引入pom依赖,springboot缓存支持和ehcache <!-- Spring Boot 缓存--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-c...
  • 1、ehcache的依赖pom.xml <!-- caching --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> ...
  • 1、CacheManagerSpring Boot默认集成CacheManager,如下包所示:可以看出springboot自动配置了 JcacheCacheConfiguration、 EhCacheCacheConfiguration、HazelcastCacheConfiguration、GuavaCacheConfiguration、...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 4,241
精华内容 1,696
关键字:

springboot整合ehcache

spring 订阅
友情链接: Chat.rar