今天这篇文章简单介绍一下,如何在SpringBoot中使用本地缓存,其实本地缓存的解决方案也有很多种,像Ehcache,GuavaCache,JCache等,这篇文章先介绍和第一种方案整合,关于Ehcache相关的理论知识,大家可以去参考这个博文 http://raychase.iteye.com/blog/1545906 写的比较详细,下面直接进入主题,上代码,看一下整体项目结构
首先看一下pom.xml的配置文件内容
4.0.0
spring_boot_cache
org.springframework.boot
spring-boot-starter-parent
1.5.2.RELEASE
UTF-8
UTF-8
1.8
org.springframework.boot
spring-boot-starter-data-jpa
mysql
mysql-connector-java
5.1.36
runtime
com.alibaba
druid
1.1.5
org.springframework.boot
spring-boot-starter-cache
net.sf.ehcache
ehcache
org.projectlombok
lombok
provided
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
引入的是cache相关依赖的jar,和用来简化javabean的相关操作,主要是通过注解来简化我们的冗余代码:
首先定义Person.java:
package com.springboot.bean;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import javax.persistence.*;
/**
* @Author 18011618
* @Description 定义用户实体信息
* @Date 14:12 2018/7/17
* @Modify By
*/
@Entity
@Table(name = "user")
@ToString
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Setter
@Getter
private Long id;
@Column(name = "username")
@Setter
@Getter
private String username;
public Person(Long id, String username) {
super();
this.id = id;
this.username = username;
}
public Person() {
super();
}
}
上面的注解有两大类,一类是基于JPA的,还有的一类是基于lombok的常用注解,下面简单把lombok做一个介绍
Lombok是一个可以通过简单的注解形式来帮助我们简化消除一些必须有但显得很臃肿的Java代码的工具,通过使用对应的注解,可以在编译源码的时候生成对应的方法。
前提:对于idea或者eclplise想使用它的话,都需要装这个插件,然后重启开发工具即可
各个版本下载地址: https://github.com/mplushnikov/lombok-intellij-plugin/releases
@Getter and @Setter
你可以用@Getter / @Setter注释任何字段(当然也可以注释到类上的),让lombok自动生成默认的getter / setter方法。
默认生成的方法是public的,如果要修改方法修饰符可以设置AccessLevel的值,例如:@Getter(access = AccessLevel.PROTECTED)
@ToString
生成toString()方法,默认情况下,它会按顺序(以逗号分隔)打印你的类名称以及每个字段。可以这样设置不包含哪些字段@ToString(exclude = "id") / @ToString(exclude = {"id","name"})
如果继承的有父类的话,可以设置callSuper 让其调用父类的toString()方法,例如:@ToString(callSuper = true)
@EqualsAndHashCode
生成hashCode()和equals()方法,默认情况下,它将使用所有非静态,非transient字段。但可以通过在可选的exclude参数中来排除更多字段。或者,通过在parameter参数中命名它们来准确指定希望使用哪些字段。
@NoArgsConstructor:生成一个没有参数的构造器
@RequiredArgsConstructor:生成指定字段的参数的构造器
@AllArgsConstructor:生成所有字段的参数的构造器
@Data:包含@ToString、@EqualsAndHashCode、@Getter / @Setter和@RequiredArgsConstructor的功能
@Accessors:主要用于控制生成的getter和setter方法
主要参数介绍
fluent boolean值,默认为false。此字段主要为控制生成的getter和setter方法前面是否带get/set
chain boolean值,默认false。如果设置为true,setter返回的是此对象,方便链式调用方法
prefix 设置前缀 例如:@Accessors(prefix = "ccc") private String cccAge 当生成get/set方法时,会把此前缀去掉
上面就是它的常用注解,可以简化Javabean的操作,节省了很多时间,建议开发中使用它
定义数据访问层接口:
package com.springboot.dao;
import com.springboot.bean.Person;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
/**
* @Author 18011618
* @Date 9:50 2018/7/9
* @Function 定义数据访问接口
*/
@Repository
public interface PersonRepository extends CrudRepository {
}
定义服务接口:
package com.springboot.service;
import com.springboot.bean.Person;
/**
* @Author 18011618
* @Description
* @Date 14:18 2018/7/17
* @Modify By
*/
public interface IPersonService {
/**
* 根据用户ID查询用户
* @param id
* @return
*/
Person findOne(Long id);
/**
* 保存一个用户信息
* @param person
* @return
*/
Person saveOne(Person person);
/**
* 删除一个用户信息
* @param id
*/
void deleteOne(Long id);
}
接口的实现:
package com.springboot.service;
import com.springboot.bean.Person;
import com.springboot.dao.PersonRepository;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
/**
* @Author 18011618
* @Description
* @Date 14:20 2018/7/17
* @Modify By
*/
@Service
@Slf4j
@CacheConfig(cacheNames = {"userCache"})
public class PersonService implements IPersonService {
private static final String CACHE_KEY = "'person'";//这里一定要加单引号,否则会被当做一个正常的字符串来识别
private static final String CACHE_NAME = "userCache";//对应ehcache.xml中cache的name
@Autowired
@Setter
private PersonRepository personRepository;
@Cacheable(value=CACHE_NAME,key="'person_'+#id")
@Override
public Person findOne(Long id) {
log.info("查询功能,缓存未找到,直接读取数据库,ID为:" + id);
return this.personRepository.findOne(id);
}
@CachePut(value=CACHE_NAME,key=CACHE_KEY)
@Override
public Person saveOne(Person person) {
log.info("新增功能,同步到缓存,直接写入数据库,ID为:" + person.getId());
return this.personRepository.save(person);
}
@CacheEvict(value=CACHE_NAME,key="'person_'+#id")
@Override
public void deleteOne(Long id) {
log.info("删除功能,删除缓存,直接删除数据库数据,ID为:" + id);
this.personRepository.delete(id);
}
}
这里出现了好几个新注解:
@Slf4j:基于lombok的log注解,可以直接使用log.info,log.debug…等方法
@CacheConfig: 指定缓存配置的名称,这里可以配置多个,多个用逗号分开
private static final String CACHE_KEY = "'person'";这个地方要特别注意,一定要写单引号,否则表达式会把它当做一个正常的字符串来解析的
@Cacheable:类或者方法上,类代表所有的方法都使用它,方法上针对特定的方法,作用就是先查询缓存是否有值,有的话就直接返回缓存结果
@CachePut:标注在方法上, Spring在每次执行前都会检查Cache中是否存在相同key的缓存元素,如果存在就不再执行该方法,而是直接从缓存中获取结果进行返回,否则才会执行并将返回结果存入指定的缓存中
@CacheEvict:标注在方法或类上,做值的清除
上面三个注解有几个公有的参数:
value():值必须填写,是指定属于ehcache.xml中cache的name,可以是多个
key:自定义策略和默认策略
自定义策略:使用方法参数时我们可以直接使用“#参数名”或者“#p参数index”
condition:指定缓存的条件
定义测试的controller:
package com.springboot.controller;
import com.springboot.bean.Person;
import com.springboot.service.IPersonService;
import lombok.Setter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* @Author 18011618
* @Description 测试controller
* @Date 14:31 2018/7/17
* @Modify By
*/
@RestController
public class PersonControoler {
@Autowired
@Setter
private IPersonService personService;
/**
* 查询用户
* @param id
* @return
*/
@GetMapping("/findPerson/{id}")
public Person find(@PathVariable Long id){
return personService.findOne(id);
}
/**
* 保存用户
* @param id
* @param username
* @return
*/
@GetMapping("/save")
public Person save(@RequestParam Long id,@RequestParam String username){
return personService.saveOne(new Person(id,username));
}
/**
* 删除用户
* @param id
* @return
*/
@GetMapping("del/{id}")
public String delete(@PathVariable Long id){
personService.deleteOne(id);
return "delete success";
}
}
定义启动应用类:
package com.springboot;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.condition.*;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.*;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.web.bind.annotation.*;
/**
* @Author 18011618
* @Description
* @Date 13:52 2018/7/17
* @Modify By
*/
@SpringBootApplication
public class CacheApplication {
public static void main(String[] args) {
SpringApplication.run(CacheApplication.class,args);
}
}
定义缓存对应的配置文件:ehcache.xml
内容如下所示:
当然这里配置的参数是比较少的,很多都是使用了默认值,它的默认参数有很多,下面简单做个介绍:
ehcache.xml配置文件详解
diskStore:为缓存路径,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. The default value is false.
diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
clearOnFlush:内存数量最大时是否清除。
再看一下对应全局配置文件:application.yaml
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver #加载数据库的驱动
filters: stat,wall,log4j #过滤类型
initialSize: 5 #资源池初始化大小
maxActive: 20 #资源池最大激活数
maxOpenPreparedStatements: 20
maxWait: 60000 #最大等待时间
minEvictableIdleTimeMillis: 300000
minIdle: 1 #最小空闲数量
password: 123123
poolPreparedStatements: true
testOnBorrow: false
testOnReturn: false
testWhileIdle: true
timeBetweenEvictionRunsMillis: 60000
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://localhost:3306/emp
username: root
validationQuery: select 'x'
logSlowSql: true
jpa:
hibernate:
ddl-auto: update
show-sql: false
cache:
type: ehcache #指定缓存类型
ehcache:
config: classpath:ehcache.xml #缓存加载配置文件
server:
port: 8888
logging:
file: cache.log
level: info
最后写一个测试类来看看测试效果:
import com.springboot.CacheApplication;
import com.springboot.bean.Person;
import com.springboot.service.IPersonService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* @Author 18011618
* @Description
* @Date 15:20 2018/7/17
* @Modify By
*/
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = CacheApplication.class)
public class CacheTest {
@Autowired
private IPersonService personService;
@Test
public void testCache(){
Person person = new Person(Long.valueOf(8),"abcd");
personService.saveOne(person);
for (int i=0;i<4;i++){
Person p = personService.findOne(Long.valueOf(8));
System.err.println("从缓存中获取数据:"+p);
}
}
}
最后看一下测试的效果:
然后看一下控制台打印的消息
至此和ehcache整合就介绍完了.
版权声明:转载请标明博客地址,谢谢!