前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >springboot(5)--缓存

springboot(5)--缓存

作者头像
叔牙
发布2020-11-19 15:13:32
4720
发布2020-11-19 15:13:32
举报
文章被收录于专栏:一个执拗的后端搬砖工

缓存是应对高并发查询的利器,传统的spring使用缓存配置稍显笨重,springboot与缓存的结合使用,往往只需要添加依赖增加一行注解就能满足我们的基本使用。常用的缓存有ehcache,guava cache,memcached,redis以及caffeine等等。此篇我们结合springboot分析一下ehcache,caffeine和redis缓存的使用方式。

springboot&ehcache

EhCache 是一个纯Java的进程内缓存框架,具有快速、精干等特点,是Hibernate中默认的CacheProvider。Ehcache是一种广泛使用的开 源Java分布式缓存。主要面向通用缓存,Java EE和轻量级容器。它具有内存和磁盘存储,缓存加载器,缓存扩展,缓存异常处理程序,一个gzip缓存servlet过滤器,支持REST和SOAP api等特点。

1.添加ehcache依赖

推荐使用的是ehcache2.x:

<!--开启 cache 缓存-->

<dependency>

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

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

</dependency>

<!-- ehcache 缓存 -->

<dependency>

<groupId>net.sf.ehcache</groupId>

<artifactId>ehcache</artifactId>

</dependency>

2.添加ehcache配置文件

在src/resources目录添加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">

<defaultCache

eternal="false"

maxElementsInMemory="1000"

overflowToDisk="false"

diskPersistent="false"

timeToIdleSeconds="0"

timeToLiveSeconds="600"

memoryStoreEvictionPolicy="LRU" />

<!-- 这里的 users 缓存空间是为了下面的 demo 做准备 -->

<cache

name="users"

eternal="false"

maxElementsInMemory="100"

overflowToDisk="false"

diskPersistent="false"

timeToIdleSeconds="0"

timeToLiveSeconds="300"

memoryStoreEvictionPolicy="LRU" />

</ehcache>

3.启用缓存

在应用启动类上增加启用缓存注解:

@EnableCaching

4.编写测试代码

缓存一般加在service层:

@Service

@Slf4j

public class UserService {

private static final String DEMO_CACHE_NAME = "users";

@Autowired

private UserDao userDao;

@Cacheable(value = DEMO_CACHE_NAME,key = "'user_' + #id")

public List<User> findById(Long id) {

log.info("UserService.findById query from DB;id={}",id);

return this.userDao.findById(id);

}

}

请求入口controller:

@RestController

@RequestMapping("/user")

public class UserController {

@Autowired

private UserService userService;

@GetMapping("/{id}")

public Object queryUser(@PathVariable("id") Long id) {

return this.userService.findById(id);

}

}

5.运行&测试

运行应用启动类,浏览器输入http://localhost:8080/user/1:

观察应用访问日志:

第一次查询查询了DB。再次刷新页面发送请求:

没有打印访问DB的日志,也就是第一次请求之后把数据放入的缓存,第二次访问的时候直接从缓存取数据,缓存生效。

springboot&caffeine

Caffeine是使用Java8对Guava缓存的重写版本,在Spring Boot 2.0中将取代Guava。如果出现Caffeine,CaffeineCacheManager将会自动配置。springboot2.0.5依赖的基础库是spring5.x,而spring5中已经取消了对guava缓存的支持。

1.添加caffeine依赖

<!--开启 cache 缓存-->

<dependency>

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

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

</dependency>

<!-- caffeine -->

<dependency>

<groupId>com.github.ben-manes.caffeine</groupId>

<artifactId>caffeine</artifactId>

</dependency>

2.增加属性配置

在主配置属性文件application.properties中增加:

spring.cache.cache-names=users

spring.cache.caffeine.spec=initialCapacity=50,maximumSize=500,expireAfterWrite=100s,refreshAfterWrite=5s

使用spring.cache.cache-names属性可以在启动时创建缓存,多个之间用逗号隔开。

3.增加caffeine配置类

CaffeineConfiguration:

@Configuration

public class CaffeineConfiguration {

/**

* 必须要指定这个Bean,refreshAfterWrite=5s这个配置属性才生效

* @return

*/

@Bean

public CacheLoader<Object, Object> cacheLoader() {

CacheLoader<Object, Object> cacheLoader = new CacheLoader<Object, Object>() {

@Override

public Object load(Object key) throws Exception {

return null;

}

// 重写这个方法将oldValue值返回回去,进而刷新缓存

@Override

public Object reload(Object key, Object oldValue) throws Exception {

return oldValue;

}

};

return cacheLoader;

}

}

4.运行&测试

业务代码service层和controller等不用调整。运行应用启动类,浏览器输入http://localhost:8080/user/1:

观察应用访问日志:

第一次查询查询了DB。再次刷新页面发送请求:

没有打印访问DB的日志,访问的时候直接从缓存取数据,也就说明我们配置的caffeine缓存生效。

springboot&redis

前边两种方式都是进程缓存,对于分布式架构盛行的时代,分布式缓存redis大放异彩。

1.添加redis缓存依赖

<!-- redis -->

<dependency>

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

<artifactId>spring-boot-starter-data-redis</artifactId>

</dependency>

<dependency>

<groupId>com.alibaba</groupId>

<artifactId>fastjson</artifactId>

</dependency>

2.增加属性配置

在src/resources/application.properties中增加redis连接配置:

# Redis数据库索引(默认为0)

spring.redis.database=0

# Redis服务器地址

spring.redis.host=119.23.232.185

# Redis服务器连接端口

spring.redis.port=6379

# Redis服务器连接密码(默认为空)

spring.redis.password=bhx5211314

# 连接池最大连接数(使用负值表示没有限制)

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=1000

3.增加redis缓存配置类

使用FastJson代替默认的序列化方式:

public class FastJsonRedisSerializer<T> implements RedisSerializer<T> {

public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");

private Class<T> clazz;

public FastJsonRedisSerializer(Class<T> clazz) {

super();

this.clazz = clazz;

}

@Override

public byte[] serialize(T t) throws SerializationException {

if (null == t) {

return new byte[0];

}

return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);

}

@Override

public T deserialize(byte[] bytes) throws SerializationException {

if (null == bytes || bytes.length <= 0) {

return null;

}

String str = new String(bytes, DEFAULT_CHARSET);

return (T) JSON.parseObject(str, clazz);

}

}

配置自定义序列化方式:

@Configuration

@ConditionalOnClass(RedisOperations.class)

@EnableConfigurationProperties(RedisProperties.class)

public class RedisConfiguration extends RedisAutoConfiguration {

@Bean

@ConditionalOnMissingBean(name = "redisTemplate")

public RedisTemplate<Object, Object> redisTemplate(

RedisConnectionFactory redisConnectionFactory) {

RedisTemplate<Object, Object> template = new RedisTemplate<>();

//使用fastjson序列化

FastJsonRedisSerializer fastJsonRedisSerializer = new FastJsonRedisSerializer(Object.class);

// value值的序列化采用fastJsonRedisSerializer

template.setValueSerializer(fastJsonRedisSerializer);

template.setHashValueSerializer(fastJsonRedisSerializer);

// key的序列化采用StringRedisSerializer

template.setKeySerializer(new StringRedisSerializer());

template.setHashKeySerializer(new StringRedisSerializer());

template.setConnectionFactory(redisConnectionFactory);

return template;

}

@Bean

@ConditionalOnMissingBean(StringRedisTemplate.class)

public StringRedisTemplate stringRedisTemplate(

RedisConnectionFactory redisConnectionFactory) {

StringRedisTemplate template = new StringRedisTemplate();

template.setConnectionFactory(redisConnectionFactory);

return template;

}

}

4.运行&测试

业务代码不用修改。运行应用启动类,在发送请求之前查看redis是否存储的内容:

没有我们定义的users开头的缓存,浏览器输入http://localhost:8080/user/1:

观察应用访问日志:

第一次查询查询了DB。再次刷新页面发送请求:

没有打印访问DB的日志,访问的时候直接从缓存取数据,也就说明我们配置的缓存生效。这时我们再次查看redis存储的内容:

我们从DB查询的数据已经存储到了redis中。

总结

合理的使用缓存,能够提高应用的性能和吞吐能力,但是缓存的滥用也会带来分布式环境下数据不一致问题,具体springboot编程时,选择使用哪一种缓存方式,还需要根据具体业务场景判定。还有其他几种常用的缓存此处不在一一列举其使用方式,如果感兴趣可以自己实现一下memcached缓存等。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-10-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 PersistentCoder 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 Redis
腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档