SpringBoot中引入Ehcache3.x

1.Ehcache介绍java

Ehcache是一个用Java实现的简单、高速、线程安全的缓存管理类库。具体快速、简单、低消耗、依赖性小、扩展性强、支持对象或序列化缓存、支持缓存或元素的失效、提供LRU/LFU/FIFO缓存策略、支持内存缓存及磁盘缓存、采用分布式缓存机制等特色。redis

2.引入依赖spring

在项目的pom.xml中添加下面这三个依赖:数据库

< dependency>api

< groupId>javax.cache < /groupId>浏览器

< artifactId>cache-api < /artifactId>缓存

< /dependency>安全

< dependency>服务器

< groupId>org.ehcache< /groupId>app

< artifactId>ehcache< /artifactId>

< version>3.7.0< /version>

< /dependency>

< dependency>

< groupId>org.springframework.boot< /groupId>

< artifactId>spring-boot-starter-cache< /artifactId>

< /dependency>

cache-api是JSR-107 Cache的规范,定义了一列接口规范(可是这只是一种规范,须要使用它的实现,例如ehcache3.x、Hazelcast等)。 ehcache是ehcache的功能包。

springBoot要支持第三方缓存的话,还须要引入spring-boot-starter-cache。

3.配置属性

3.1 配置application.properties

在application.properties添加以下配置:

可选,配置了spring.cache.jcache.config属性会自动装配JCacheCacheManager

spring.cache.type=jcache

指定ehcache的配置文件所在的位置

spring.cache.jcache.config=classpath:ehcache-3.x.xml

3.2配置ehcache-3.x.xml

在resources文件夹下新建ehcache-3.x.xml,添加以下内容:

< ?xml version="1.0" encoding="UTF-8" ?>

< eh:config

xmlns:xsi='www.w3.org/2001/XMLSch…'

xmlns:eh='www.ehcache.org/v3'

xsi:schemaLocation="www.ehcache.org/v3 www.ehcache.org/schema/ehca…">

< !--指定缓存目录-->

< eh:persistence directory="${java.io.tmpdir}/cache-data"/>

< !--缓存模板-->

< eh:cache-template name="default">

< eh:expiry>

< eh:ttl unit="seconds">600< /eh:ttl>

< /eh:expiry>

< eh:resources>

< !--堆内内存能够放2000个条目,超出部分堆外100MB-->

< eh:heap unit="entries">2000< /eh:heap>

< eh:offheap unit="MB">100< /eh:offheap>

< /eh:resources>

< /eh:cache-template>

< !--实际的缓存区间,继承了default缓存模板,sample彻底使用模板默认-->

< eh:cache alias="sample" uses-template="default">< /eh:cache>

< !--下面两个继承了default缓存模板,但覆盖了缓存的过时时间--> < eh:cache alias="authority_service" uses-template="default">

< eh:expiry>

< eh:ttl unit="hours">1< /eh:ttl>

< /eh:expiry>

< /eh:cache>

< eh:cache alias="shop_service" uses-template="default">

< eh:expiry>

< eh:ttl unit="hours">24< /eh:ttl>

< /eh:expiry>

< /eh:cache>

< /eh:config>

更多配置知识,请参考ehcache官网:ehcache XML配置

4.使用示例

4.1 准备一个controller

该controller只有一个方法,得到某类商品的列表:

@RestController

@Validated

@RequestMapping("/v1.0/api/shop")

public class ShopController {

@Autowired

ShopService shopService;

@RequestMapping(value = {"/commodity"}, method = RequestMethod.GET)

public List listCommodity (@RequestParam String type) {

System.out.println("ShopController: type is " + type);

return shopService.listCommodity(type);

}

}

4.2 准备一个service

在须要使用缓存的Bean上面添加@EnableCaching注解,那该bean具备缓存功能。 在须要使用缓存的方法上添加@Cacheable注解,那该方法具备缓存功能(前提是该bean具备缓存的功能)。 注意: 1和2配合起来才能使某个bean的某个方法具备缓存的功能。

package com.example.demo.service;

import org.springframework.cache.annotation.Cacheable;

import org.springframework.cache.annotation.EnableCaching;

import org.springframework.stereotype.Service;

import java.util.ArrayList;

import java.util.List;

@Service

@EnableCaching

public class ShopService {

// value:使用叫作'shop_service'的缓存器

// key: 缓存的key等于#type,即传入的key值

// condition:缓存的条件,当#type等于phone时,才进行缓存

@Cacheable(cacheNames = "shop_service", key = "#type", condition = "#type == 'phone'")

public List listCommodity(String type) {

System.out.println("ShopService: 调用了listCommodity");

List commodities = new ArrayList<>();

if (type.equals("phone")) {

commodities.add("Apple");

commodities.add("HuaWei");

} else {

commodities.add("others");

}

return commodities;

}

}

4.3 启动springBoot,进行测试

使用浏览器,发送4个请求:

http://localhost:8080/v1.0/api/shop/commodity?type=phone

http://localhost:8080/v1.0/api/shop/commodity?type=phone

http://localhost:8080/v1.0/api/shop/commodity?type=computer

http://localhost:8080/v1.0/api/shop/commodity?type=computer

后台打印的日志以下:

ShopController: type is phone

ShopService: 调用了listCommodity

ShopController: type is phone

ShopController: type is computer

ShopService: 调用了listCommodity

ShopController: type is computer

ShopService: 调用了listCommodity

4.4 结果分析

第一次发送请求,符合缓存的条件,因为没有缓存,因而执行了service的逻辑,并将结果缓存到了ehcache中。

第二次发送请求,符合缓存的条件,因为已经缓存告终果,直接从ehcache中拿取缓存的结果返回,没有进入到service的逻辑。

第三次和第四次都不符合缓存的条件,须要进入到service的逻辑计算结果。

5.Ehcache使用场景

使用的过程当中,根据优势和缺点进行权衡后再应用到项目中去,Ehcache缓存也是如此,在实际工做有不少使用场景,一般将Ehcache做为Redis的二次缓存使用。

5.1 Ehcache的适用场景

(1) 比较少的更新数据表的状况下

Ehcache做为Hibernate的缓存时,在进行修改表数据(save、update、delete等)的时候,Ehcache会自动把缓存中关于此表的全部缓存所有删除掉,这样作只是能达到同步,但对于数据常常修改的表来讲,可能就失去了缓存的意义了。

(2)对一致性要求不高的状况下

由于Ehcache本地缓存的特性,目前没法很好的解决不一样服务器缓存同步的问题,因此在一致性要求高的场合下,建议使用Redis、Memcached等集中式缓存。

5.2Ehcache的缺陷

(1) 缓存漂移

每一个应用节点只管理本身的缓存,在更新某个节点的时候,不会影响到其余的节点,这样数据之间可能就不一样步了。

(2) 数据库瓶颈

对于单实例的应用来讲,缓存能够保护数据库的读风暴;可是在集群的环境下,每个应用节点都要按期保存数据更新,节点越多,要维持这样的状况对数据库的开销也越大。

5.3 Ehcache的正确打开方式

咱们在项目中使用集中式缓存(Redis或Memcached等)一般都是检查缓存中是否存在指望的数据,若是存在直接将数据返回,若是不存在就查询数据库而后再将数据缓存,然后将结果返回。这时候若是缓存系统由于某些缘由宕机,形成服务没法访问,那么大量的请求将直接穿透到数据库,对数据库形成巨大的压力。

针对上述状况,咱们有多种可行的解决方法,其中一种方案是将Ehcache做为集中式缓存的二级本地缓存,这样当缓存系统宕机后,服务器应用的本地缓存还能继续抗住大量请求。

使用了Ehcache做为本地缓存后,可能会出现本地缓存与缓存系统之间出现数据不一致的状况,由于本地缓存是在服务器应用中存在,在实际生产环境中一定是多台服务器分别部署,如何可以在更新缓存系统数据的同时,也可以更新Ehcache的缓存数据,以及保证不一样服务器间Ehcache本地缓存数据的同步问题。

通常有两种解决方案可供参考:

第一种:定时轮询

每台应用服务器定时轮询Redis缓存,更新本地的Ehcache缓存。

第二种:主动通知

每台应用服务器的Ehcache同步侦听MQ消息,经过MQ推送的方式,将redis中更新的缓存数据推送到每台应用服务器中。

针对上述的分析,可造成以下的缓存方案:

缓存方案.jpg
相关文章
相关标签/搜索