一:前言
- 在我们编写的应用中,组件一般都是无状态的,一个请求过来,经过逻辑处理返回所需要的结果,但下一次再来的相同请求的时候,需要再走一边流程。对于所需求的结果,我们可能需要经过计算/访问数据库/远程服务调用来获取,但对于结果变更不频繁的,做相同的事就是资源浪费。
- 解决方案:缓存,现在主流的缓存是Encache和Redis,我就这两个为例。
二:缓存情况说明
- 下列是缓存使用的时候使用的注解
注解 | 作用 |
---|---|
@Cacheable | 调用方法前,先查看缓存,没有在方法返回结果添加入缓存 |
@CachPut | 将返回结果放到缓存,调用前不检查缓存 |
@CacheEvict | 清除缓存中一个或者多个数据 |
@Caching | 分组注解,能同时应用多个 |
- 缓存管理器
缓存管理器是缓存的抽象表现,我们做demo时使用的Spring Boot,默认缓存管理器为ConcurrentMapCacheManager。So,我们需要自己配置自己所需要的缓存管理器EhCacheCacheManager和RedisCacheManager。同时,我们需要将@EnableCaching添加在启动类或者配置类上,本质上就是创建一个切面,根据方法上的注释来进行处理。 - 缓存建立流程
- 声明我们要用什么类型的缓存,默认/Ehcache/Redis,并对它进行配置,缓存大小,过期时间等等。
- 我们需要开启缓存,也就是添加@EnableCaching。
- 我们通过添加注解来决定对数据进行怎样的操作。
三:Demo
这里有个前提:我在mybatis-plus搭建了对数据库的访问
pom文件:
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.0.5</version>
</dependency>
yml配置:
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
username: root
password: root
url: jdbc:mysql://localhost:3306/mybatisplus
UserMapper:
@Repository
public interface UserMapper extends BaseMapper<User> {
}
开启扫描:
@SpringBootApplication
@MapperScan("com.lll.springbootspringmvcdemo.mapper")
public class SpringbootSpringmvcDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootSpringmvcDemoApplication.class, args);
}
}
3.1 Ehcache
POM文件:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>2.10.6</version>
</dependency>
yml配置文件:
spring:
cache:
ehcache:
config:
classpath: ehcache.xml
type: ehcache
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">
<!--配置一个最简单的缓存-->
<cache name="user" maxElementsInMemory="1000" />
</ehcache>
<!--
cache的属性说明:
name:缓存的名称。
maxElementsInMemory:缓存中最大元素个数。0表示不限制
eternal:对象是否永久有效,一但设置了,timeout将不起作用,元素永久存在。
clearOnFlush:内存数量最大时是否清除。
timeToIdleSeconds : 设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。
diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
diskPersistent:是否在VM重启时存储硬盘的缓存数据。默认值是false。
maxElementsOnDisk:硬盘最大缓存个数。
overflowToDisk:当内存中对象数量达到maxElementsInMemory时,Ehcache将会对象写到磁盘中。
diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
maxEntriesLocalDisk:当内存中对象数量达到maxElementsInMemory时,Ehcache将会对象写到磁盘中。
memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
-->
开启缓存:
@SpringBootApplication
@EnableCaching
@MapperScan("com.lll.springbootspringmvcdemo.mapper")
public class SpringbootSpringmvcDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootSpringmvcDemoApplication.class, args);
}
}
UserService:
@Slf4j
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
@Cacheable(value = "user")
public User GetUser(Integer Uid){
log.info("跑方法,没有跑缓存");
return userMapper.selectById(Uid);
}
}
测试:
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringbootSpringmvcDemoApplicationTests {
@Autowired
private UserService userService;
@Test
public void contextLoads() {
for (int i = 0; i < 5; i++) {
User user = userService.GetUser(1);
System.out.println(user);
}
}
}
3.2 Redis
POM文件:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
yml配置:
## Redis 配置
## Redis数据库索引(默认为0)
# spring.redis.database=0
## Redis服务器地址
# spring.redis.host=127.0.0.1
## Redis服务器连接端口
# spring.redis.port=6379
## Redis服务器连接密码(默认为空)
# spring.redis.password=
## 连接池最大连接数(使用负值表示没有限制)
#spring.redis.pool.max-active=8
## 连接池最大阻塞等待时间(使用负值表示没有限制)
# spring.redis.pool.max-wait=-1
## 连接池中的最大空闲连接
#spring.redis.pool.max-idle=8
## 连接池中的最小空闲连接
#spring.redis.pool.min-idle=0
## 连接超时时间(毫秒)
#spring.redis.timeout=1200
spring:
redis:
password:
database: 0
host: localhost
port: 6379
jedis:
pool:
max-active: 8
max-wait: -1
max-idle: 8
min-idle: 0
timeout: 1200
spring:
cache:
type: redis
mybatis-plus:
configuration:
cache-enabled: true
RedisCacheManager定制类:
当我们使用引入redis的starter时,容器中默认使用的是RedisCacheManager。它在操作redis时使用的是RedisTemplate<Object, Object>,默认采用JDK的序列化机制
@Configuration
public class RedisConfig {
/**
* 序列化缓存定制
* @param factory
* @return
*/
@Bean
public RedisCacheManager jsonCacheManager(RedisConnectionFactory factory) {
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.serializeValuesWith(RedisSerializationContext.SerializationPair
.fromSerializer(new GenericJackson2JsonRedisSerializer()));
return RedisCacheManager.builder(factory).cacheDefaults(config).build();
}
}
其他一切跟上面一样。