SpringBoot系列——使用技巧之方法添加缓存功能
一、文章概述
各位小伙伴,在JAVA编程中,肯定常常会遇到某个方法因处理时间较为缓慢,如果每次调用都重新进行响应处理,较为浪费性能和时间。本文教大家使用老生常谈的Springboot + Spring data redis缓存技术实现简单的方法调用,有兴趣的同志,可详细探究哈!!!
文章书写不易,点个关注不迷路哦,O(∩_∩)O哈哈~
二、准备工作
- 开发环境
java 1.8
springboot2.0版本
maven
三、具体实现
1. 导入依赖
导入相关依赖,cache、spring data redis
<!-- spring-boot-starter-cache -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
<version>2.7.4</version>
</dependency>
<!-- spring-data-redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.7.4</version>
</dependency>
2. 添加redis配置
在application中添加redis配置和使用缓存
spring:
# 指明使用什么作为缓存存储
cache:
type: redis
# 配置redis,具体需要什么配置,这个根据项目需求自行添加配置
redis:
host: 192.168.2.156
port: 32190
database: 2
jedis:
pool:
max-active: 200
max-wait: -1
min-idle: 10
timeout: 2000
3. 添加缓存配置类
该配置类,主要配置内容为:自定义缓存配置,自定义缓存key生成器,任选一种即可
关于什么是缓存配置、key生成器,这个大家自行了解一下,这里就不多赘述啦_
- 使用默认的缓存配置
import org.springframework.boot.autoconfigure.cache.CacheManagerCustomizer;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.lang.reflect.Method;
/**
* 缓存配置类
*/
@Configuration
public class CacheManagerConfig {
/**
* 自定义缓存配置
* <cacheManager.setAllowNullValues(false)> 设置不对null值使用缓存 </>
* <其他需求配置自行选择>
* @return
*/
@Bean
public CacheManagerCustomizer<ConcurrentMapCacheManager> cacheManagerCustomizer() {
return new CacheManagerCustomizer<ConcurrentMapCacheManager>() {
public void customize(ConcurrentMapCacheManager cacheManager) {
cacheManager.setAllowNullValues(false);
}
};
}
/**
* 自定义key配置
* @return
*/
@Bean
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
public Object generate(Object target, Method method, Object... params) {
/**
* 配置key的生成策略为:方法名称+“-”+参数列表,返回内容自己定,想要啥就咋配置
*/
return method.getName() + "-" + params.toString();
}
};
}
}
- 带有缓存过期的缓存配置
package com.king.fun.test.cofig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.cache.CacheManagerCustomizer;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ResourceLoader;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import java.lang.reflect.Method;
import java.time.Duration;
/**
* 缓存配置类
*/
@Configuration
public class CacheManagerConfig {
@Autowired
private ResourceLoader resourceLoader;
/**
* 有缓存过期时间的缓存配置
* @param connectionFactory
* @return
*/
@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) {
return RedisCacheManager.builder(connectionFactory)
.cacheDefaults(RedisCacheConfiguration.defaultCacheConfig(resourceLoader.getClassLoader()).entryTtl(Duration.ofHours(2))) // 获取默认缓存配置,设置缓存过期时间
.transactionAware() // 在spring事务提交时才进行数据缓存
.build();
}
/**
* 自定义key配置
* @return
*/
@Bean(value = "myKeyGenerator")
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
public Object generate(Object target, Method method, Object... params) {
/**
* 配置key的生成策略为:方法名称+“-”+参数列表,返回内容自己定,想要啥就咋配置
*/
return method.getName() + "-" + params.toString();
}
};
}
}
4. 配置redis连接池
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
@Configuration
public class JedisConfig {
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private int port;
@Value("${spring.redis.jedis.pool.max-active}")
private int maxActive;
@Value("${spring.redis.jedis.pool.max-wait}")
private int maxWait;
@Value("${spring.redis.jedis.pool.max-idle}")
private int maxIdle;
@Value("${spring.redis.jedis.pool.min-idle}")
private int minIdle;
@Value("${spring.redis.timeout}")
private int timeout;
@Bean
public JedisPool jedisPoolFactory() {
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxIdle(maxIdle);
jedisPoolConfig.setMinIdle(minIdle);
jedisPoolConfig.setMaxWaitMillis(maxWait);
jedisPoolConfig.setMaxTotal(maxActive);
JedisPool jedisPool = new JedisPool(jedisPoolConfig, host, port, timeout, null);
Logger logger = LoggerFactory.getLogger(JedisPool.class);
logger.info("redis连接成功:{} {}", host, port);
return jedisPool;
}
}
5. 方法添加注解实现缓存
-
关于缓存注解
@EnableCaching:
开关性注解,在项目启动类或某个配置类上使用此注解后,则表示允许使用注解的方式进行缓存操作
@Cacheable:
可用于类或方法上;在目标方法执行前,会根据key先去缓存中查询看是否有数据,有就直接
返回缓存中的key对应的value值。不再执行目标方法;无则执行目标方法,并将方法的返回值
作为value,并以键值对的形式存入缓存@CachePut:
可用于类或方法上;在执行完目标方法后,并将方法的返回值作为value,并以键值对的形式存入缓存中
@CacheEvice:
可用于类或方法上;在执行完目标方法后,清除缓存中对应key的数据
@Caching:
此注解用作复杂缓存配置情形,可组合@Cacheable、@CacheEvict、@CachePut三种注解任意几种使用
@CacheConfig:
用于配置一些公共的属性
-
本文主要使用的注解
-
启动类添加开启缓存支持
@EnableCaching
-
方法添加缓存注解
@Cacheable 对使用的方法添加缓存功能,主要属性如下 value / cacheNames:缓存名字 key:存储在缓存中的数据key,可以用来判定或获取数据等 keyGenerator:使用的key生成器,可使用自定义的/Spel表达式/或默认的 unless:是否缓存方法的返回值,true为不缓存 condition:满足什么条件才会进行缓存 注意:key与keyGenerator不能同时使用!
-
-
实现代码
在需要使用缓存的方法上添加@Cacheable注解,即可解锁方法缓存功能,如下:
/** * 返回名字 * @return */ @Cacheable(cacheNames = "getName", keyGenerator = "myKeyGenerator") public String getName(int key) { System.out.println("缓存在不存在该key:"+key); return persionName.get(key); }
6. 测试代码
不知道怎么用的小伙伴,给大家提供一个简单的测试代码。但是工作中,大家完成以上配置后,肯定不会这么简单调用,在自己工程中灵活使用即可,但是要想用的出神入化,还需要深入了解缓存技术以及redis缓存雪崩等各类问题。
import org.springframework.cache.annotation.Cacheable;
import java.util.HashMap;
import java.util.Map;
public class CacheUtils {
static final Map<Integer, String> persionName = new HashMap<Integer, String>(){};
static {
persionName.put(1, "JAVA");
persionName.put(2, "PYTHON");
persionName.put(3, "GO");
}
/**
* 返回名字
* @return
*/
@Cacheable(cacheNames = "getName", keyGenerator = "myKeyGenerator")
public String getName(int key) {
System.out.println("缓存在不存在该key:"+key);
return persionName.get(key);
}
/**
* 此处为调用main函数,注意不能将这个调用放在方法同类中,因为缓存注解本质是基于Spring AOP切面,必须走代理才能生效,如果是同类方法调用或子类调用父类缓存方法都属于内部调用,缓存不会生效
**/
public static void main(String[] args) {
// 这里调用两次如果没有缓存,那么测试方法中的语句将会打印2遍,反之则1遍
String name = new CacheUtils().getName(1);
String name1 = new CacheUtils().getName(1);
}
}
通过Spring data redis实现的缓存仅为个人想法,如果有其他好的想法,欢迎评论区交流。