这几天在开发的项目中,考虑引入一些缓存机制。顺便又了解了一下spring-boot的缓存、以及JSR107、ehcache。并做了一些使用实例。
spring-boot缓存使用实例
spring-boot中引入依赖spring-boot-starter-cache
,pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
/**
* 启动类
*/
@SpringBootApplication
@EnableAutoConfiguration
@EnableCaching // 启用缓存
public class Application extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
}
/**
* restful类
*/
@RestController
public class SampleController {
@Autowired
private SampleServiceImpl sampleService;
@RequestMapping("/sample/test")
public BaseQueryParam test(BaseQueryParam dto) {
return sampleService.testCache(dto);
}
}
@Service
public class SampleServiceImpl {
// 取第一个参数可以用这几种姿势#root.args[1]或#p0或#a0
@Cacheable(value="SampleServiceImpl", key="#p0.resourceId")
public BaseQueryParam testCache(BaseQueryParam param) {
System.out.println("第1次访问时未缓存,打印此文本");
return param;
}
}
public class BaseQueryParam {
/**
* 资源标识。主要用来标识需要访问的资源类型
*/
private String resourceId;
public String getResourceId() {
return resourceId;
}
public void setResourceId(String resourceId) {
this.resourceId = resourceId;
}
}
测试:
http://localhost:8080/sample/test?resourceId=abc
访问的时候当传入的参数resourceId一样时,第1次控制台打印“第1次访问时未缓存,打印此文本”,后面就没有打印。
生命周期:如果没检测到EhCache3,Hazelcast,Infinispan等类型,将会使用Simple类型,即使用ConcurrentHashMap进行缓存,这种类型的缓存是永久有效的。具体的使用可以参考org.springframework.cache.concurrent.ConcurrentMapCacheManager
;
使用JSR107和ehcache
JSR107的注解为@CacheResult,springboot建议不要和@Cacheable混合使用。同时改为使用ehcache来配置缓存,可以有效的管理内存的占用、缓存的生命周期等。
spring-boot中引入依赖spring-boot-starter-cache
,pom.xml
中增加:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>3.2.1</version>
</dependency>
<dependency>
<groupId>javax.cache</groupId>
<artifactId>cache-api</artifactId>
</dependency>
/**
* 启动类
*/
@SpringBootApplication
@EnableAutoConfiguration
@EnableCaching // 启用缓存
public class Application extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
}
/**
* restful类
*/
@RestController
public class SampleController {
@Autowired
private SampleServiceImpl sampleService;
@RequestMapping("/sample/test")
public BaseQueryParam test(BaseQueryParam dto) {
return sampleService.testCache(dto);
}
}
@Service
public class SampleServiceImpl {
// JSR107的注解为@CacheResult,springboot建议不要和@Cacheable混合使用
@CacheResult(cacheName = "SampleServiceImpl", cacheKeyGenerator = SampleCacheKeyGenerator.class)
public BaseQueryParam testCache(BaseQueryParam param) {
System.out.println("第1次访问时未缓存,打印此文本");
return param;
}
/**
* 用于生成key的类
*/
public static class SampleCacheKeyGenerator implements CacheKeyGenerator {
@Override
public GeneratedCacheKey generateCacheKey(CacheKeyInvocationContext<? extends Annotation> arg0) {
BaseQueryParam param = (BaseQueryParam) (arg0.getAllParameters()[0].getValue());
if (null == param) {
return null;
}
return new SampleGeneratedCacheKey(param.getResourceId());
}
}
/**
* 缓存key类
*/
public static class SampleGeneratedCacheKey implements GeneratedCacheKey {
private static final long serialVersionUID = 1L;
private final String key;
public SampleGeneratedCacheKey(String key) {
this.key = key;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((key == null) ? 0 : key.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
SampleGeneratedCacheKey other = (SampleGeneratedCacheKey) obj;
if (key == null) {
if (other.key != null)
return false;
} else if (!key.equals(other.key))
return false;
return true;
}
}
}
public class BaseQueryParam implements Serializable { // ehcache缓存必须要实现Serializable接口
/**
* 资源标识。主要用来标识需要访问的资源类型
*/
private String resourceId;
public String getResourceId() {
return resourceId;
}
public void setResourceId(String resourceId) {
this.resourceId = resourceId;
}
}
application.properties
配置:
# SampleServiceImpl 对应cacheName = "SampleServiceImpl"
spring.cache.cache-names=SampleServiceImpl
spring.cache.ehcache.config=calsspath:ehcache.xml
关于JSR107
https://jcp.org/en/jsr/detail?id=107
描述(网上抄来的):JCache规范定义了一种对Java对象临时在内存中进行缓存的方法,包括对象的创建、共享访问、假脱机(spooling)、失效、各JVM的一致性等,可被用于缓存JSP内最经常读取的数据,如产品目录和价格列表。利用JCACHE,多数查询的反应时间会因为有缓存的数据而加快(内部测试表明反应时间大约快15倍)。