看着文档学ehcache

简介:纯java实现的缓存组件(jar包),最主要的作用还是做应用内缓存(进程内),比如hibernate就默认使用ehcache做缓存。我们可以创建多个缓存(cache),缓存中以key-value的形式存储数据,数据结构较为单一。


存储位置:

heap:由GC管理的JVM堆

offheap:堆外内存(非JVM的堆)

disk:持久化到硬盘,cache.destroy()方法可以删除硬盘上的缓存


其他功能

Eviction Advisors

缓存策略,说白了就是控制哪些缓存数据可存储,哪些不可存储,比如可以只让key为偶数的存储,或者只有value为String类可以存储。我们可以定义一个实现了EvictionAdvisor接口的类来控制。


User Managed Caches

由用户自己管理的缓存,不由CacheManager管理,用户可以自己控制cache的生命周期等等。但是为了方便,一般都是由CacheManager来管理。


Transactions Support

支持事务,我觉得一般用不到,如果它仅仅是一个缓存,并且缓存的逻辑会包含在service方法里,而service方法由spring的事务来管理,那么没必要用到它。


Cache-through

包括read-through和write-through,把缓存作为SOR(system of record),我个人还没弄清楚作为系统级别的缓存数据有什么作用


ehcache与redis的区别

1.redis的数据结构比较丰富,有key-value、hash、set等;ehcache比较简单,只有key-value

2.ehcache直接在jvm虚拟机中缓存,速度快,效率高;但是缓存共享麻烦,集群分布式应用不方便。redis是通过socket访问到缓存服务,效率ecache低,比数据库要快很多,处理集群和分布式缓存方便,有成熟的方案。如果是单个应用或者对缓存访问要求很高的应用,用ehcache。如果是大型系统,存在缓存共享、分布式部署、缓存内容很大的,建议用redis。


编程方式配置cache

下面是两个例子

import org.ehcache.Cache;
import org.ehcache.CacheManager;
import org.ehcache.config.builders.CacheConfigurationBuilder;
import org.ehcache.config.builders.CacheManagerBuilder;
import org.ehcache.config.builders.ResourcePoolsBuilder;
import org.junit.Test;

/**
 * writer: holien
 * Time: 2017-08-11 11:52
 * Intent: 入门测试ehcache
 */
public class EhCacheTest {
    @Test
    public void testEhcache() {
        // 创建缓存管理器和一个叫“preConfigured”的缓存实例
        CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder()
                .withCache("preConfigured",
                        CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class,
                                String.class, ResourcePoolsBuilder.heap(10)))
                .build();
        // 初始化缓存管理器
        cacheManager.init();
        Cache preConfigured = cacheManager.getCache("preConfigured", Long.class, String.class);
        preConfigured.put(1L, "zheng pens");
        // 覆盖上一个值
        preConfigured.put(1L, "pens");
        System.out.println(preConfigured.get(1L));
        System.out.println(preConfigured.containsKey(1L));
        // 不存在的key-value返回null
        System.out.println(preConfigured.get(2L));
        // 不允许值为null,报空指针错误
//      preConfigured.put(3L, null);

        // 不在创建cacheManeger时创建缓存实例,单独创建
        Cache cache2 = cacheManager.createCache("cache2",
                CacheConfigurationBuilder.newCacheConfigurationBuilder(
                        Integer.class, String.class,
                        ResourcePoolsBuilder.heap(5))
//                        .withEvictionAdvisor(new CustomEvictionAdvisor())
                        .build());

        cache2.put(100, "hello");
        System.out.println(cache2.get(100));
    }
}
这个例子中把缓存的数据存储到硬盘
import org.ehcache.PersistentUserManagedCache;
import org.ehcache.config.builders.ResourcePoolsBuilder;
import org.ehcache.config.builders.UserManagedCacheBuilder;
import org.ehcache.config.units.MemoryUnit;
import org.ehcache.core.spi.service.LocalPersistenceService;
import org.ehcache.impl.config.persistence.DefaultPersistenceConfiguration;
import org.ehcache.impl.config.persistence.UserManagedPersistenceContext;
import org.ehcache.impl.persistence.DefaultLocalPersistenceService;
import org.junit.Test;

import java.io.File;

/**
 * writer: holien
 * Time: 2017-08-11 22:40
 * Intent: 使用ehcache的持久化功能
 */
public class PersistenceCacheTest {
    @Test
    public void testPersistenceCache() throws Exception {
        LocalPersistenceService persistenceService = new DefaultLocalPersistenceService(
                new DefaultPersistenceConfiguration(new File("E:\\")));

        PersistentUserManagedCache cache = UserManagedCacheBuilder.newUserManagedCacheBuilder(Long.class, String.class)
                .with(new UserManagedPersistenceContext("persistentCache", persistenceService))
                .withResourcePools(ResourcePoolsBuilder.newResourcePoolsBuilder()
                        .disk(10L, MemoryUnit.MB, true))
                .build(true);
        // 把缓存只存进硬盘里,只要persistenceService相同,即使关闭,再次启动还是可以读取数据
        cache.put(42L, "The Answer!");
        System.out.println(cache.get(42L));
//        cache.remove(44L);

        // 手动关闭和销毁
        cache.close();
        // 删除硬盘上的缓存
//        cache.destroy();

        // 停止服务
        persistenceService.stop();
    }
}

创建CacheConfiguration时设置该缓存的entry的过期时间

.withExpiry(Expirations.timeToLiveExpiration(Duration.of(20, TimeUnit.SECONDS)))
官方实例的xml文件,各种属性作一个介绍



  
  
    
    
      
    
  

  
  

    
    java.lang.Long

    
    com.pany.domain.Product

    
      
      2
    

    
    com.pany.ehcache.OddEvictionAdvisor

    
    
      
      com.pany.ehcache.integration.ProductCacheLoaderWriter
        
    

    
    200
  

  
  
    
      
    
  

  
  
    
    java.lang.Long
    com.pany.domain.Customer
    
    200
  

使用我自己定义的ehcache.xml配置的cache



    
        java.lang.Long
        java.lang.String
        
            1000
        
        2
    

import org.ehcache.Cache;
import org.ehcache.CacheManager;
import org.ehcache.config.builders.CacheManagerBuilder;
import org.ehcache.xml.XmlConfiguration;
import org.junit.Test;

import java.net.URL;


/**
 * writer: holien
 * Time: 2017-08-13 14:24
 * Intent: 使用xml配置cache
 */
public class XmlConfugureTest {
    @Test
    public void testXmlConfiguration() throws Exception {
//        URL location = new URL("file:E:\\IdeaProjects\\ehCacheTest\\web\\ehcache.xml");
        URL location = getClass().getResource("/ehcache.xml");
        System.out.println(location.toString());
        XmlConfiguration xmlConfiguration = new XmlConfiguration(location);
        CacheManager cacheManager = CacheManagerBuilder.newCacheManager(xmlConfiguration);
        cacheManager.init();
        Cache cache = cacheManager.getCache("test", Long.class, String.class);
        cache.put(1L, "111");
        cache.put(2L, "222");
        System.out.println(cache.get(1L));
        System.out.println(cache.get(2L));
    }
}

当然,最好还是由spring管理cacheManager,然后使用xml来配置cache的属性,这样管理起来比较方便,在另一篇文章,讲讲ehcache2与spring的整合以及注解。

cache运行期间添加监听器

ListenerObject listener = new ListenerObject(); 这个ListenerObject类就是我们自己定义的继承了CacheEventAdapter抽象类的类。

cache.getRuntimeConfiguration().registerCacheEventListener(listener, EventOrdering.ORDERED,    EventFiring.ASYNCHRONOUS, EnumSet.of(EventType.CREATED, EventType.REMOVED));

cache运行期间解除监听器

cache.getRuntimeConfiguration().deregisterCacheEventListener(listener); 

官方3.1v文档说提供了CacheEventAdapter抽象类方便我们重写监听器的方法,但是CacheEventAdapter 里的方法却是protected的,只能通过下载源码,然后改写源码重新打jar包,比较麻烦,后期修改也麻烦,也许是一个bug。


总结

ehcache也有集群的功能,但是我觉得ehcache还是适合一些简单的应用缓存,比如方法级别的,缓存方法的返回值。或者当作一个Map来存储不由GC管理的、可以持久化的数据,比如爬虫url的存储。


你可能感兴趣的:(综合)