ehcache-3.x版本实战

什么是缓存呢?我们先来看一个例子

实现一个斐波那契数列--递归

 public static int fbnq(int n){
        if(n==1 || n ==2){
            return 1;
        }else{
            return fbnq(n-2)+fbnq(n-1);
        }
    }

如果我们使用debug调试进入就会发现,递归的方式需要反复计算一些值,比如fbnq(3)重复执行。每次都要重新计算,这样效率很低,于是我们想到何不把静态结果保存起来,下次用到直接取就好了,改进代码如下:

static Map map = new HashMap<>();//定义map存放每次计算的值 键是n 值是fbnQ(n)
public static int fbnq(int n) {
        if(n==1 || n==2) {
            return 1;
        } 
        Integer value = map.get(n);
        if(value == null) {
            value = fbnq(n - 1) + fbnq(n - 2);
            map.put(n, value);
        }
        return value;
    }

在使用debug调试,就会发现每值只需要计算一次,这样效率明显提高了,这段代码中map集合充当的就是一个缓存的角色。它将每次计算的值存下来,下一次如果需要就用重新计算,只需要从 map缓存中根据键 n 取值就好了。

什么是LRU,如何简单实现缓存?

LRU:最近最少使用,即最少使用的会被从缓存中移除。

举个例子:比如依次往缓存中存入键为1 2 3 4 5,那么如果此时内存不够,优先移除的元素就是1,因为他距离使用最远。

但如果在插入第6个元素之前执行过类似于查找 ---> get(1) 这类操作,也就是说1这个键最近被使用了,那么如果内存不够,需要移除元素,此时队列为 2 3 4 5 1,很显然2应该被移除。这个类似于队列,从左到右,先进先出。

上面的HashMap作为缓存并不是最好的实现,缓存是存在内存中的,所以说不能无限使用,必须定义一个限制,当达到什么条件,必须清除一些缓存。这个时候采用LinkedHashMap比较合适。

LinkedHashMap中有一个构造方法:

public LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder)

第一个参数是初始化容量,第二个参数是负载因子,最后一个参数是控制是否开启元数放入集合的顺序,默认是false,也就是

accessOrder=false //表示按顺序排列
accessOrder=true //即如果遇到get(key)方法则,调整元素在集合中的顺序, 最新访问的排在最后

 简单实现代码如下:

LinkedHashMap map = new LinkedHashMap(16, 0.75f, true){

    @Override
    protected boolean removeEldestEntry(Map.Entry eldest) {
        // 希望集合中放5个元素, 超过5个要移除最远使用的元素
        if(this.size() <= 5) {
            return false;
        } else {
            return true;
        }
    }
};

LinkedHashMap的 removeEldestEntry() 方法可以保证满足一定条件的时候返回true,触发remove集合元素

ehcache缓存3.x

ehcache是本地缓存(类似于单机模式),如果是分布式缓存一般采用redis

添加依赖



    org.ehcache
    ehcache
    3.6.3



    javax.cache
    cache-api

配置缓存文件




    //文件中可以定义多个缓存,所以需要用alias来区分
        
        java.lang.String
        java.lang.String

       
        
            60
            60
        
        
        
            200 
             
              
        
    

注意必须在标签之前定义。

// 1. 类对象.getResource() 获取类路径上的一个资源文件(url对象)
URL url = GunsApplication.class.getResource("/ehcache.xml");

// 2. 准备配置对象
XmlConfiguration config = new XmlConfiguration(url);

// 3. 创建一个新的缓存管理器类
CacheManager cacheManager = CacheManagerBuilder.newCacheManager(config);

// 4. 初始化缓存管理器
cacheManager.init();//一定要初始化,否则会报错。

// 5. 获取缓存对象
Cache cache = cacheManager.getCache("cache1", String.class, String.class);

// 6. 存储键值
cache.put("xi,an", "西安");

// 7. 根据键获取值
System.out.println(cache.get("xi,an"));

// 8. 删除键
cache.remove("xi,an");
System.out.println(cache.get("xi,an"));

// 9. 清空缓存
cache.clear();

SpringBoot整合ehcache

application.yml配置:

spring:
  cache:
    jcache:
      config: classpath:ehcache.xml

记得加入classpath:表示ehcache.xml在根路径下

@EnableCaching  

将@EnableCaching定义在SpringBoot启动类上,相当于启用缓存功能,内部就会创建 CacheManager(注意是spring框架的), 并交给spring容器管理。

在需要开启缓存的方法上方加上:@Cacheable(cacheNames="缓存名(在配置文件中定义的)",key = 与配置文件中的value相对(类型) )
注意key=的写法一般写字符串类型 如: 

key = "'dept_' + #deptId" (springEL表达式)

除此之外:@CacheEvict ,写在需要删除缓存的方法上,用来删除某个key value,或者清空整个缓存, 用在执行了数据的增删改时,这三种情况下,都应该让缓存失效。

缓存执行流程:

 1) 先访问的是设置缓存类的代理对象 (由于cglib 生成该类的子类对象作为代理对象)。
 2) 代理对象重写了目标方法, 在该方法内, 通过缓存管理器(cache)找对应缓存名称的缓存。
 3) Cache.get(key)去获取value, 第一次访问value为空, 执行的是原本的方法。
 4) 该类的方法返回结果作为value放入缓存中。
 5) 第二次访问的时候,先访问的是该类的代理对象。
 6) 代理对象重写了目标方法,方法内部,通过缓存管理器(cacheManager)找到对应缓存。
 7) Cache.get(key)去获取对应value, 返回value不为空,直接返回缓存中的value, 没有执行原本的方法,而是执行代理对象中的目标方法。

缓存一般使用在读多写少的程序中。 

你可能感兴趣的:(ehcache-3.x版本实战)