Guava Cache本地缓存在 Spring Boot应用中的实践
概述
在如今高并发的互联网应用中,缓存的地位举足轻重,对提升程序性能帮助不小。而 3.x开始的 Spring也引入了对 Cache的支持,那对于如今发展得如火如荼的 Spring Boot来说自然也是支持缓存特性的。当然 Spring Boot默认使用的是 SimpleCacheConfiguration
,即使用 ConcurrentMapCacheManager
来实现的缓存。但本文将讲述如何将 Guava Cache缓存应用到 Spring Boot应用中。
Guava Cache是一个全内存的本地缓存实现,而且提供了线程安全机制,所以特别适合于代码中已经预料到某些值会被多次调用的场景
下文就上手来摸一摸它,结合对数据库的操作,我们让 Guava Cache作为本地缓存来看一下效果!
注: 本文首发于 My Personal Blog:CodeSheep·程序羊,欢迎光临 小站
准备工作
- 准备好数据库和数据表并插入相应实验数据(MySQL)
比如我这里准备了一张用户表,包含几条记录:
我们将通过模拟数据库的存取操作来看看 Guava Cache缓存加入后的效果。
搭建工程:Springboot + MyBatis + MySQL + Guava Cache
pom.xml 中添加如下依赖:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--for mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<!--for Mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- Spring boot Cache-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<!--for guava cache-->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>27.0.1-jre</version>
</dependency>
</dependencies>
建立 Guava Cache配置类
引入 Guava Cache的配置文件 GuavaCacheConfig
@Configuration
@EnableCaching
public class GuavaCacheConfig {
@Bean
public CacheManager cacheManager() {
GuavaCacheManager cacheManager = new GuavaCacheManager();
cacheManager.setCacheBuilder(
CacheBuilder.newBuilder().
expireAfterWrite(10, TimeUnit.SECONDS).
maximumSize(1000));
return cacheManager;
}
}
Guava Cache配置十分简洁,比如上面的代码配置缓存存活时间为 10 秒,缓存最大数目为 1000 个
配置 application.properties
server.port=82
# Mysql 数据源配置
spring.datasource.url=jdbc:mysql://121.116.23.145:3306/demo?useUnicode=true&characterEncoding=utf-8&useSSL=false
spring.datasource.username=root
spring.datasource.password=xxxxxx
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
# mybatis配置
mybatis.type-aliases-package=cn.codesheep.springbt_guava_cache.entity
mybatis.mapper-locations=classpath:mapper/*.xml
mybatis.configuration.map-underscore-to-camel-case=true
编写数据库操作和 Guava Cache缓存的业务代码
- 编写 entity
public class User {
private Long userId;
private String userName;
private Integer userAge;
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public Integer getUserAge() {
return userAge;
}
public void setUserAge(Integer userAge) {
this.userAge = userAge;
}
}
- 编写 mapper
public interface UserMapper {
List<User> getUsers();
int addUser(User user);
List<User> getUsersByName( String userName );
}
- 编写 service
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public List<User> getUsers() {
return userMapper.getUsers();
}
public int addUser( User user ) {
return userMapper.addUser(user);
}
@Cacheable(value = "user", key = "#userName")
public List<User> getUsersByName( String userName ) {
List<User> users = userMapper.getUsersByName( userName );
System.out.println( "从数据库读取,而非读取缓存!" );
return users;
}
}
看得很明白了,我们在 getUsersByName
接口上添加了注解:@Cacheable
。这是 缓存的使用注解之一,除此之外常用的还有 @CachePut
和 @CacheEvit
,分别简单介绍一下:
@Cacheable
:配置在getUsersByName
方法上表示其返回值将被加入缓存。同时在查询时,会先从缓存中获取,若不存在才再发起对数据库的访问@CachePut
:配置于方法上时,能够根据参数定义条件来进行缓存,其与@Cacheable
不同的是使用@CachePut
标注的方法在执行前不会去检查缓存中是否存在之前执行过的结果,而是每次都会执行该方法,并将执行结果以键值对的形式存入指定的缓存中,所以主要用于数据新增和修改操作上@CacheEvict
:配置于方法上时,表示从缓存中移除相应数据。
- 编写 controller
@RestController
public class UserController {
@Autowired
private UserService userService;
@Autowired
CacheManager cacheManager;
@RequestMapping( value = "/getusersbyname", method = RequestMethod.POST)
public List<User> geUsersByName( @RequestBody User user ) {
System.out.println( "-------------------------------------------" );
System.out.println("call /getusersbyname");
System.out.println(cacheManager.toString());
List<User> users = userService.getUsersByName( user.getUserName() );
return users;
}
}
改造 Spring Boot应用主类
主要是在启动类上通过 @EnableCaching注解来显式地开启缓存功能
@SpringBootApplication
@MapperScan("cn.codesheep.springbt_guava_cache")
@EnableCaching
public class SpringbtGuavaCacheApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbtGuavaCacheApplication.class, args);
}
}
最终完工的整个工程的结构如下:
实际实验
通过多次向接口 localhost:82/getusersbyname
POST数据来观察效果:
可以看到缓存的启用和失效时的效果如下所示(上文 Guava Cache的配置文件中设置了缓存 user的实效时间为 10s):
怎么样,缓存的作用还是很明显的吧!
后 记
由于能力有限,若有错误或者不当之处,还请大家批评指正,一起学习交流!
- My Personal Blog:CodeSheep 程序羊
- 程序羊的 2018年终总(gen)结(feng)

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
-
上一篇
迅速搞懂JavaScript正则表达式之方法
咱们来看看JavaScript中都有哪些操作正则的方法。 RegExp RegExp 是正则表达式的构造函数。 使用构造函数创建正则表达式有多种写法: new RegExp('abc'); // /abc/ new RegExp('abc', 'gi'); // /abc/gi new RegExp(/abc/gi); // /abc/gi new RegExp(/abc/m, 'gi'); // /abc/gi 它接受两个参数:第一个参数是匹配模式,可以是字符串也可以是正则表达式;第二个参数是修饰符。 如果第一个参数的正则表达式定义了修饰符,第二个参数又有值,则以第二个参数定义的修饰符为准,这是ES2015的新特性。 使用构造函数一般用于需要动态构造正则表达式的场景,性能不如字面量写法。 我们来看看它的实例属性: lastIndex属性。它的作用是全局匹配时标记下一次匹配开始的位置,全局匹配的抓手就是它。 source属性。它的作用是存储正则模式的主体。比如 /abc/gi 中的 abc 。 对应的修饰符属性。目前有 global 、 ignoreCase 、 mul...
-
下一篇
从2018年以太坊统计数据看区块链发展趋势
在2018年结束时,我们处于长期“加密货币冬天”的尾声,2017年末至今的市场波动已经引起了区块链行业的普遍关注。然而,仔细研究这些数字可以发现一种强大的技术,它充斥着项目和开发人员,并且在新的一年里有着坚定的上升发展轨迹。 交易活动 迄今为止,以太坊网络共处理了超过3.53亿笔交易。自6月1日以来,这一交易量增加了超过1亿笔(占总交易量的2.4亿笔)。1月4日,该网络在24小时内处理了130万笔交易,这是有史以来最多的一天。自6月1日起,平均每日交易量约为610,000来源。 在以太坊的价值交易中潜水更多,我们看到在2017年末和2018年初的“繁荣”之后网络的相对稳定性。从2018年3月开始,网络稳定在每月交易的约5000万ETH,并且名义上有波动从那以后每个月。自第三季度以来,每月的交易数量略有下降,从7月的每月约2000万减少到11月的每月约1600万。每个交易的平均ETH在同一时间段内有所增加,然而,从11月ETH/交易的2倍到ETH/交易的不到2倍[图1]。 图1.以太坊交易数据2017年12月——2018年11月。Alethio数据科学。 以太坊区块链上有近4900万个唯...
相关文章
文章评论
共有0条评论来说两句吧...