缓存相信各位同学都或多或少用到过,毕竟不能把所有压力都给数据库。今天来简单总结一下下在Spring Boot中使用Redis和EhCache缓存O(∩_∩)O~
Spring Boot本身是支持多种缓存实现的,其中提供了4个注解来帮助大家使用缓存:
先说一下EhCache,EhCache是在内存中的缓存,也就是说,程序在,缓存就在,程序停了,缓存就没了,要使用EhCache,首先引入pom starter:
org.springframework.boot
spring-boot-starter-cache
在启动类上开启缓存支持:
@SpringBootApplication
@EnableCaching
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
下来只需要在方法上加上注解就行了:
@Cacheable(value="user",key = "#user.id")
public User findOne(User user) {
User u=userRepository.findOne(user.getId());
return u;
}
可以看到,在注解中指定了value和key两个参数,value是用来归类用的,以上方法所生成的所有缓存在缓存库中都存放在user文件夹下;key是用来指定缓存键值的,它有两种生成策略——默认策略和自定义策略,其默认策略如下:
很明显,我这里自定义了key,指定为参数user对象的id。
key支持通过Sping EL表达式来指定,几个一看就懂的栗子:
@Cacheable(value="user", key="#id")
public User find(Integer id) {
return null;
}
@Cacheable(value="user", key="#p0")
public User find(Integer id) {
return null;
}
@Cacheable(value="user", key="#user.id")
public User find(User user) {
return null;
}
@Cacheable(value="user", key="#p0.id")
public User find(User user) {
return null;
}
除了上述使用方法参数生成key以外,Spring还提供了一个root对象来生成key:
属性名称 | 描述 | 示例 |
---|---|---|
methodName | 当前方法名 | #root.methodName |
method | 当前方法 | #root.method.name |
target | 当前被调用的对象 | #root.target |
targetClass | 当前被调用的对象的class | #root.targetClass |
args | 当前方法参数组成的数组 | #root.args[0] |
caches | 当前被调用的方法使用的Cache | #root.caches[0].name |
另外,如果EhCache有别的设置,那么可以新建一个ehcache.xml,在application.properties中配好这个配置文件即可:
spring.cache.type=ehcache
spring.cache.ehcache.config=static/ehcache.xml
下面说一下Redis,同样首先引入pom starter:
org.springframework.boot
spring-boot-starter-data-redis
同样通过@EnableCaching打开缓存支持。
由于Redis是独立安装的,它就像数据库一样可以持久化数据,所以必然也像数据库一样有连接地址,在application.yml中配置如下:
spring:
redis:
database: 0
host: 10.155.20.162
port: 6379
pool:
max-active: 80
max-wait: -1
max-idle: 80
min-idle: 0
timeout: 5000
呐,EhCache的时候用的properties配置文件,Redis用的yml配置文件哟,各取所爱吧~
同样在方法上面使用@Cacheable、@CacheEvict、@CachePut来操作缓存。
这里介绍一下keyGenerator,前面key的生成策略就是它控制的,Spring允许我们自定义这个Generator,举个栗子:
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport{
//自定义key生成方式
@Bean
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
@Override
public Object generate(Object target, Method method, Object... params) {
StringBuilder sb = new StringBuilder();
String[] value = new String[1];
Cacheable cacheable = method.getAnnotation(Cacheable.class);
if (cacheable != null) {
value = cacheable.value();
}
CachePut cachePut = method.getAnnotation(CachePut.class);
if (cachePut != null) {
value = cachePut.value();
}
CacheEvict cacheEvict = method.getAnnotation(CacheEvict.class);
if (cacheEvict != null) {
value = cacheEvict.value();
}
sb.append(value[0]);
sb.append(":");
sb.append(params[0].toString());
return sb.toString();
}
};
}
//缓存管理器
@Bean
public CacheManager cacheManager(@SuppressWarnings("rawtypes") RedisTemplate redisTemplate) {
RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);
cacheManager.setDefaultExpiration(43200); //设置缓存过期时间
return cacheManager;
}
@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory factory){
StringRedisTemplate template = new StringRedisTemplate(factory);
@SuppressWarnings({ "rawtypes", "unchecked" })
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
template.setValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
}
可以看到,这个Config中有3个Bean,第1个Bean中用注解的value属性+":"+第一个参数作为key值的生成策略;第2个Bean中指定了缓存的全局过期时间;第3个Bean中定义了RedisTemplate。
ok,以上讲了通过注解来操作缓存,不过有的时候,并不一定存在方法,只是单纯地想操作某个key值的缓存,咋办?这个时候就要用到RedisTemplate啦,Spring中自带这个对象,包括上面也自定义了这个对象,我们在需要使用的地方把它注入进来就可以了。不过,通常我们会先写个工具类:
@Service
public class RedisService {
@Autowired
@Qualifier("stringRedisTemplate")
RedisTemplate template;
public void setValue(String key, Object val) {
template.opsForValue().set(key, val);
}
public void setValue(String key, Object val, int time, TimeUnit unit) {
template.opsForValue().set(key, val, time, unit);
}
public Object getValue(String key) {
return template.opsForValue().get(key);
}
public void deleteValue(String key){
template.delete(key);
}
}
可以看到,我这边使用的是stringRedisTemplate,具体还有什么其它类型,各位同学自己去发现一以下吧~