|
Spring Boot集成EHCache实现缓存机制 我们先说说这一篇文章我们都会学到的技术点:Spring Data JPA,SpringBoot使用Mysql,Spring MVC,EHCache,Spring Cache等 (其中@Cacheable请看上一节的理论知识) ,具体分如下几个步骤:
(1)新建Maven Java Project
(2)在pom.xml中加入依赖包
(3)编写Spring Boot启动类;
(4)配置application.properties;
(5)编写缓存配置类以及ehcache.xml配置文件;
(6)编写DemoInfo实体类进行测试;
(7)编写持久类DemoInfoRepository;
(8)编写处理类DemoInfoService;
(9)编写DemoInfoController测试类;
(10)运行测试;
以上就是具体的步骤了,那么接下来我们一起按照这个步骤来进行实现吧。
(1)新建Maven Java Project
新建一个工程名为spring-boot-ehcache的maven java project。
(2)在pom.xml中加入依赖包
在pom.xml文件中加入相应的依赖包,SpringBoot父节点依赖包;spring boot web支持;缓存依赖spring-context-support;集成ehcache需要的依赖;JPA操作数据库;mysql 数据库驱动,具体pom.xml文件:
< project xmlns= "http://maven.apache.org/POM/4.0.0" xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation= "http://maven.apache.org/POM/4.0.0http://maven.apache.org/xsd/maven-4.0.0.xsd" >
< modelVersion >4.0.0 </ modelVersion >
< groupId >com.kfit </ groupId >
< artifactId >spring-boot-<u>ehcache</u> </ artifactId >
< version >0.0.1-SNAPSHOT </ version >
< packaging >jar </ packaging >
< name >spring-boot-<u>ehcache</u> </ name >
< url >http://maven.apache.org </ url >
< properties >
< project.build.sourceEncoding >UTF-8 </ project.build.sourceEncoding >
<!-- 配置JDK编译版本. -->
< java.version >1.8 </ java.version >
</ properties >
<!-- springboot 父节点依赖,
引入这个之后相关的引入就不需要添加version配置,
spring boot 会自动选择最合适的版本进行添加。
-->
< parent >
< groupId >org.springframework.boot </ groupId >
< artifactId >spring-boot-starter-parent </ artifactId >
< version >1.3.3.RELEASE </ version >
</ parent >
< dependencies >
<!-- 单元测试. -->
< dependency >
< groupId ><u>junit</u> </ groupId >
< artifactId ><u>junit</u> </ artifactId >
< scope >test </ scope >
</ dependency >
<!-- springboot web 支持:<u>mvc</u>,<u>aop</u>... -->
< dependency >
< groupId >org.springframework.boot </ groupId >
< artifactId >spring-boot-starter-web </ artifactId >
</ dependency >
<!--
包含支持UI模版(Velocity,FreeMarker,JasperReports),
邮件服务,
脚本服务(JRuby),
缓存Cache(EHCache),
任务计划Scheduling(<u>uartz</u>)。
-->
< dependency >
< groupId >org.springframework </ groupId >
< artifactId >spring-context-support </ artifactId >
</ dependency >
<!-- 集成<u>ehcache</u>需要的依赖-->
< dependency >
< groupId >net.sf.ehcache </ groupId >
< artifactId ><u>ehcache</u> </ artifactId >
</ dependency >
<!-- JPA 操作数据库. -->
< dependency >
< groupId >org.springframework.boot </ groupId >
< artifactId >spring-boot-starter-data-<u>jpa</u> </ artifactId >
</ dependency >
<!-- <u>mysql</u> 数据库驱动. -->
< dependency >
< groupId ><u>mysql</u> </ groupId >
< artifactId ><u>mysql</u>-connector-java </ artifactId >
</ dependency >
<!-- Spring boot 单元测试. -->
< dependency >
< groupId >org.springframework.boot </ groupId >
< artifactId >spring-boot-starter-test </ artifactId >
< scope >test </ scope >
</ dependency >
</ dependencies >
</ project > |
(3)编写Spring Boot启动类(com.kfit.App.java);
package com.kfit;
importorg.springframework.boot.SpringApplication;
importorg.springframework.boot.autoconfigure.SpringBootApplication;
/**
*
*
* @SpringBootApplication 申明让spring boot 自动给程序进行必要的配置,
*
@SpringBootApplication
等价于:
@Configuration
@EnableAutoConfiguration
@ComponentScan
*
* @author Angel(QQ:412887952)
* @version v.0.1
*/
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App. class, args);
}
}
(4)配置application.properties;
在application.properties中主要配置数据库连接和JPA的基本配置,具体如下:
Src/main/resouces/application.properties :
########################################################
###datasource ,mysql 数据库连接配置
########################################################
spring.datasource.url = jdbc:mysql://localhost:3306/test
spring.datasource.username = root
spring.datasource.password = root
spring.datasource.driverClassName = com.mysql.jdbc.Driver
spring.datasource.max-active = 20
spring.datasource.max-idle = 8
spring.datasource.min-idle = 8
spring.datasource.initial-size = 10
########################################################
### Java Persistence Api ,JPA自动建表操作配置
########################################################
# Specify the DBMS
spring.jpa.database = MYSQL
# Show or not log for each sqlquery
spring.jpa.show-sql = true
# Hibernate ddl auto (create,create-drop, update)
spring.jpa.hibernate.ddl-auto = update
# Naming strategy
spring.jpa.hibernate.naming-strategy = org.hibernate.cfg.ImprovedNamingStrategy
# stripped before adding them tothe entity manager)
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect |
(5)编写缓存配置类以及ehcache.xml配置文件:
这个类主要是注册缓存管理对象EhCacheCacheManager、缓存工厂对象EhCacheManagerFactoryBean,具体代码如下:
EhCacheManagerFactoryBean:
package com.kfit.config;
importorg.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.ehcache.EhCacheCacheManager;
importorg.springframework.cache.ehcache.EhCacheManagerFactoryBean;
importorg.springframework.context.annotation.Bean;
importorg.springframework.context.annotation.Configuration;
importorg.springframework.core.io.ClassPathResource;
/**
* 缓存配置.
* @author Angel(QQ:412887952)
* @version v.0.1
*/
@Configuration
@EnableCaching // 标注启动缓存.
public class CacheConfiguration {
/**
* <u>ehcache</u> 主要的管理器
* @param bean
* @return
*/
@Bean
publicEhCacheCacheManager ehCacheCacheManager(EhCacheManagerFactoryBean bean){
System. out.println( "CacheConfiguration.ehCacheCacheManager()");
return newEhCacheCacheManager( bean.getObject());
}
/*
* 据shared与否的设置,
* Spring 分别通过CacheManager.create()
* 或new CacheManager()方式来创建一个<u>ehcache</u>基地.
*
* 也说是说通过这个来设置cache的基地是这里的Spring独用,还是跟别的(如<u>hibernate</u>的<u>Ehcache</u>共享)
*
*/
@Bean
public EhCacheManagerFactoryBean ehCacheManagerFactoryBean(){
System. out.println( "CacheConfiguration.ehCacheManagerFactoryBean()");
EhCacheManagerFactoryBean cacheManagerFactoryBean = newEhCacheManagerFactoryBean ();
cacheManagerFactoryBean.setConfigLocation ( newClassPathResource( "conf/ehcache.xml"));
cacheManagerFactoryBean.setShared( true);
return cacheManagerFactoryBean;
}
} |
在src/main/resouces/conf下编写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. Thedefault value is false.
diskSpoolBufferSizeMB :这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
diskExpiryThreadIntervalSeconds :磁盘失效线程运行时间间隔,默认是120秒。
memoryStoreEvictionPolicy :当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
clearOnFlush :内存数量最大时是否清除。
memoryStoreEvictionPolicy: 可选策略有:LRU(最近最少使用,默认策略)、FIFO(先进先出)、LFU(最少访问次数)。
FIFO ,first in firstout,这个是大家最熟的,先进先出。
LFU , Less FrequentlyUsed,就是上面例子中使用的策略,直白一点就是讲一直以来最少被使用的。如上面所讲,缓存的元素有一个hit属性,hit值最小的将会被清出缓存。
LRU ,Least RecentlyUsed,最近最少使用的,缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。
-->
< defaultCache
eternal= "false"
maxElementsInMemory= "1000"
overflowToDisk= "false"
diskPersistent= "false"
timeToIdleSeconds= "0"
timeToLiveSeconds= "600"
memoryStoreEvictionPolicy= "LRU" />
< cache
name= "demo"
eternal= "false"
maxElementsInMemory= "100"
overflowToDisk= "false"
diskPersistent= "false"
timeToIdleSeconds= "0"
timeToLiveSeconds= "300"
memoryStoreEvictionPolicy= "LRU" />
</ ehcache > |
(6)编写DemoInfo实体类进行测试;
在com.kfit.bean下编写DemoInfo实体类进行缓存测试:
package com.kfit.bean;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
/**
* 测试实体类.
* @author Angel(QQ:412887952)
* @version v.0.1
*/
@Entity
public class DemoInfo {
@Id @GeneratedValue
private long id; // 主键.
private String name; // 名称;
private String pwd; // 密码;
private int state;
public long getId() {
return id;
}
public void setId( long id)
{
this. id = id;
}
public String getName(){
return name;
}
public void setName(String name) {
this. name = name;
}
public String getPwd(){
return pwd;
}
public void setPwd(String pwd) {
this. pwd = pwd;
}
public int getState() {
return state;
}
public void setState( int state)
{
this. state = state;
}
@Override
public StringtoString() {
return "DemoInfo[id=" + id + ", name="
+ name + ", pwd=" + pwd + ", state=" + state + "]";
}
} |
(7)编写持久类DemoInfoRepository;
编写持久类DemoInfoRepository:
com.kfit.repository.DemoInfoRepository:
package com.kfit.repository;
importorg.springframework.data.repository.CrudRepository;
import com.kfit.bean.DemoInfo;
/**
* 操作数据库.
* @author Angel(QQ:412887952)
* @version v.0.1
*/
public interfaceDemoInfoRepository extends CrudRepository<DemoInfo,Long>{
} |
(8)编写处理类DemoInfoService;
编写增删改查的方法,在这几个方法中都使用注解缓存,进行缓存的创建以及删除,修改等操作:
com.kfit.service.DemoInfoService :
package com.kfit.service;
import com.kfit.bean.DemoInfo;
import javassist.NotFoundException;
public interface DemoInfoService{
void delete(Long id);
DemoInfoupdate(DemoInfo updated) throws NotFoundException;
DemoInfofindById(Long id);
DemoInfosave(DemoInfo demoInfo);
}
com.kfit.service.impl.DemoInfoServiceImpl:
package com.kfit.service.impl;
import javax.annotation.Resource;
importorg.springframework.cache.annotation.CacheEvict;
importorg.springframework.cache.annotation.CachePut;
importorg.springframework.cache.annotation.Cacheable;
importorg.springframework.stereotype.Service;
import com.kfit.bean.DemoInfo;
import com.kfit.repository.DemoInfoRepository;
import com.kfit.service.DemoInfoService;
import javassist.NotFoundException;
@Service
public class DemoInfoServiceImpl implements DemoInfoService{
// 这里的单引号不能少,否则会报错,被识别是一个对象;
public static final String CACHE_KEY
= "'demoInfo'";
@Resource
private DemoInfoRepository demoInfoRepository;
/**
* value 属性表示使用哪个缓存策略,缓存策略在ehcache.xml
*/
public static final String DEMO_CACHE_NAME
= "demo";
/**
* 保存数据.
* @param demoInfo
*/
@CacheEvict(value= DEMO_CACHE_NAME,key= CACHE_KEY)
@Override
public DemoInfosave(DemoInfo demoInfo){
return demoInfoRepository.save( demoInfo);
}
/**
* 查询数据.
* @param id
* @return
*/
@Cacheable(value= DEMO_CACHE_NAME,key= "'demoInfo_'+#id")
@Override
public DemoInfofindById(Long id){
System. err.println( " 没有走缓存!"+ id);
return demoInfoRepository.findOne( id);
}
/**
* http://www.mincoder.com/article/2096.shtml:
*
* 修改数据.
*
* 在支持Spring Cache的环境下,对于使用@Cacheable标注的方法,Spring在每次执行前都会检查Cache中是否存在相同key的缓存元素,如果存在就不再执行该方法,而是直接从缓存中获取结果进行返回,否则才会执行并将返回结果存入指定的缓存中。@CachePut也可以声明一个方法支持缓存功能。与@Cacheable不同的是使用@CachePut标注的方法在执行前不会去检查缓存中是否存在之前执行过的结果,而是每次都会执行该方法,并将执行结果以键值对的形式存入指定的缓存中。
@CachePut 也可以标注在类上和方法上 。使用@CachePut时我们可以指定的属性跟@Cacheable是一样的。
*
* @param updated
* @return
*
* @throws NotFoundException
*/
@CachePut(value = DEMO_CACHE_NAME,key = "'demoInfo_'+#updated.getId()")
//@CacheEvict(value= DEMO_CACHE_NAME,key = "'demoInfo_'+#updated.getId()")// 这是清除缓存.
@Override
public DemoInfoupdate(DemoInfo updated) throws NotFoundException{
DemoInfo demoInfo = demoInfoRepository.findOne( updated.getId());
if( demoInfo == null){
throw newNotFoundException( "No find");
}
demoInfo.setName( updated.getName());
demoInfo.setPwd( updated.getPwd());
return demoInfo;
}
/**
* 删除数据.
* @param id
*/
@CacheEvict(value = DEMO_CACHE_NAME,key = "'demoInfo_'+#id") // 这是清除缓存.
@Override
public void delete(Long id){
demoInfoRepository.delete( id);
}
} |
(9)编写DemoInfoController测试类;
编写一个rest进行测试:
com.kfit.controller.DemoInfoController :
package com.kfit.controller;
import javax.annotation.Resource;
importorg.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.kfit.bean.DemoInfo;
import com.kfit.service.DemoInfoService;
import javassist.NotFoundException;
@RestController
public class DemoInfoController {
@Resource
private DemoInfoService demoInfoService;
@RequestMapping( "/test")
public String test(){
// 存入两条数据.
DemoInfo demoInfo = new DemoInfo();
demoInfo.setName( " 张三");
demoInfo.setPwd( "123456");
DemoInfo demoInfo2 = demoInfoService.save( demoInfo);
// 不走缓存.
System. out.println( demoInfoService.findById( demoInfo2.getId()));
// 走缓存.
System. out.println( demoInfoService.findById( demoInfo2.getId()));
demoInfo = new DemoInfo();
demoInfo.setName( " 李四");
demoInfo.setPwd( "123456");
DemoInfo demoInfo3 = demoInfoService.save( demoInfo);
// 不走缓存.
System. out.println( demoInfoService.findById( demoInfo3.getId()));
// 走缓存.
System. out.println( demoInfoService.findById( demoInfo3.getId()));
System. out.println( "============ 修改数据=====================");
// 修改数据.
DemoInfo updated = new DemoInfo();
updated.setName( " 李四-updated");
updated.setPwd( "123456");
updated.setId( demoInfo3.getId());
try {
System. out.println( demoInfoService.update( updated));
} catch(NotFoundException e) {
e.printStackTrace();
}
// 不走缓存.
System. out.println( demoInfoService.findById( updated.getId()));
return "ok";
}
} |
(10)运行测试;
运行App.java进行测试,访问:http://127.0.0.1:8080/test 进行测试,主要是观察控制台的打印信息。
Hibernate: insert into demo_info(name, pwd, state) values (?, ?, ?)
没有走缓存!52
DemoInfo [id=52, name=张三, pwd=123456,state=0]
DemoInfo [id=52, name=张三, pwd=123456,state=0]
Hibernate: insert into demo_info(name, pwd, state) values (?, ?, ?)
没有走缓存!53
DemoInfo [id=53, name=李四, pwd=123456,state=0]
DemoInfo [id=53, name=李四, pwd=123456,state=0]
============修改数据=====================
DemoInfo [id=53, name=李四-updated,pwd=123456, state=0]
DemoInfo [id=53, name=李四-updated,pwd=123456, state=0]
C:\Users\ADMINI~1.ANG\AppData\Local\Temp\
Hibernate: insert into demo_info(name, pwd, state) values (?, ?, ?)
没有走缓存!54
DemoInfo [id=54, name=张三, pwd=123456,state=0]
DemoInfo [id=54, name=张三, pwd=123456,state=0]
Hibernate: insert into demo_info(name, pwd, state) values (?, ?, ?)
没有走缓存!55
DemoInfo [id=55, name=李四, pwd=123456,state=0]
DemoInfo [id=55, name=李四, pwd=123456,state=0]
============修改数据=====================
DemoInfo [id=55, name=李四-updated,pwd=123456, state=0]
DemoInfo[id=55, name=李四-updated,pwd=123456, state=0]
----------------------------
原文链接:https://blog.csdn.net/linxingliang/article/details/52263773
程序猿的技术大观园:www.javathinker.net
[这个贴子最后由 flybird 在 2020-03-28 12:26:18 重新编辑]
|
|