依賴
<!--cache-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
配置
關於 SpringBoot
中配置 Redis
,本文不在贅述,請看:SpringBoot2.0.X配置Redis,本文配置也是在這個上面進行改造的。
1、啓用緩存,在 Application
上添加 @EnableCaching
註解。
/*
* 啓用緩存功能
* */
@EnableCaching
public class BuildingApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication application = new SpringApplication(BuildingApplication.class);
SpringApplication.run(BuildingApplication.class, args);
}
}
2、使 RedisConfig
繼承 CachingConfigurerSupport
,重寫 keyGenerator
方法,並緩存配置管理器
。
RedisConfig.java
/**
* Redis配置
* <p>
* 創建人:leigq <br>
* 創建時間:2018-11-08 10:11 <br>
* <p>
* 修改人: <br>
* 修改時間: <br>
* 修改備註: <br>
* </p>
*/
@Configuration
public class RedisConfig extends CachingConfigurerSupport {
/**
* 自定義緩存key的生成策略。默認的生成策略是看不懂的(亂碼內容) 通過Spring 的依賴注入特性進行自定義的配置注入並且此類是一個配置類可以更多程度的自定義配置
* <br/>
* 配置參考:https://www.cnblogs.com/taiyonghai/p/9454764.html
* <br/>
* 使用參考:
* <ul>
* <li>
* <a href='http://blog.didispace.com/springbootcache2/'>Spring Boot中的緩存支持(二)使用Redis做集中式緩存</a>
* </li>
* <li>
* <a href='http://blog.didispace.com/springbootcache1/'>Spring Boot中的緩存支持(一)註解配置與EhCache使用</a>
* </li>
* </ul>
* <p>
*/
@Bean(name = "redisCacheKeyGenerator")
@Primary
@Override
public KeyGenerator keyGenerator() {
return (target, method, params) -> {
StringBuilder sb = new StringBuilder();
sb.append(target.getClass().getName());
sb.append(method.getName());
for (Object obj : params) {
sb.append(obj.toString());
}
return sb.toString();
};
}
/**
* 緩存配置管理器
*/
@Bean(name = "redisCacheManager")
@Primary
public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
// 以鎖寫入的方式創建RedisCacheWriter對象
RedisCacheWriter writer = RedisCacheWriter.lockingRedisCacheWriter(redisConnectionFactory);
/*
設置CacheManager的Value序列化方式爲Jackson2JsonRedisSerialize,
RedisCacheConfiguration默認就是使用
StringRedisSerializer序列化key,
JdkSerializationRedisSerializer序列化value,
*/
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
objMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(objMapper);
RedisSerializationContext.SerializationPair pair = RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer);
// 創建默認緩存配置對象
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig().serializeValuesWith(pair);
return new RedisCacheManager(writer, config);
}
}
完整配置如下:
package com.blog.www.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;
/**
* Redis配置
* <p>
* 創建人:leigq <br>
* 創建時間:2018-11-08 10:11 <br>
* <p>
* 修改人: <br>
* 修改時間: <br>
* 修改備註: <br>
* </p>
*/
@Configuration
public class RedisConfig extends CachingConfigurerSupport {
/**
* 使用 JacksonConfig 中的 objMapper,兼容 java8 時間
*
* @see JacksonConfig#getObjMapper()
*/
private final ObjectMapper objMapper;
public RedisConfig(@Qualifier(value = "objMapper") ObjectMapper objMapper) {
this.objMapper = objMapper;
}
/**
* 自定義緩存key的生成策略。默認的生成策略是看不懂的(亂碼內容) 通過Spring 的依賴注入特性進行自定義的配置注入並且此類是一個配置類可以更多程度的自定義配置
* <br/>
* 配置參考:https://www.cnblogs.com/taiyonghai/p/9454764.html
* <br/>
* 使用參考:
* <ul>
* <li>
* <a href='http://blog.didispace.com/springbootcache2/'>Spring Boot中的緩存支持(二)使用Redis做集中式緩存</a>
* </li>
* <li>
* <a href='http://blog.didispace.com/springbootcache1/'>Spring Boot中的緩存支持(一)註解配置與EhCache使用</a>
* </li>
* </ul>
* <p>
*/
@Bean(name = "redisCacheKeyGenerator")
@Primary
@Override
public KeyGenerator keyGenerator() {
return (target, method, params) -> {
StringBuilder sb = new StringBuilder();
sb.append(target.getClass().getName());
sb.append(method.getName());
for (Object obj : params) {
sb.append(obj.toString());
}
return sb.toString();
};
}
/**
* 緩存配置管理器
*/
@Bean(name = "redisCacheManager")
@Primary
public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
// 以鎖寫入的方式創建RedisCacheWriter對象
RedisCacheWriter writer = RedisCacheWriter.lockingRedisCacheWriter(redisConnectionFactory);
/*
設置CacheManager的Value序列化方式爲Jackson2JsonRedisSerialize,
RedisCacheConfiguration默認就是使用
StringRedisSerializer序列化key,
JdkSerializationRedisSerializer序列化value,
*/
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
objMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(objMapper);
RedisSerializationContext.SerializationPair pair = RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer);
// 創建默認緩存配置對象
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig().serializeValuesWith(pair);
return new RedisCacheManager(writer, config);
}
/**
* redisTemplate 序列化使用的jdkSerializeable, 存儲二進制字節碼, 所以自定義序列化類, 生產環境不建議這樣
* <br/>
* 參考:https://blog.csdn.net/m0_37893932/article/details/78259288
* <br>創建人: leigq
* <br>創建時間: 2018-11-08 10:12
* <br>
*
* @param redisConnectionFactory redis連接工廠
* @return RedisTemplate
*/
@Bean(value = "redisTemp")
@Primary
public RedisTemplate<Object, Object> getRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
// 使用Jackson2JsonRedisSerialize 替換默認序列化
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
objMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(objMapper);
// 以下代碼爲將 RedisTemplate 的 Value 序列化方式由 JdkSerializationRedisSerializer更換爲 Jackson2JsonRedisSerializer
// 此種序列化方式結果清晰、容易閱讀、存儲字節少、速度快,所以推薦更換
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
// 設置 key 的序列化規則
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(new StringRedisSerializer());
// 是否啓用事務
// redisTemplate.setEnableTransactionSupport(true);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
測試
寫個簡單的根據用戶id查詢用戶信息,使用 @Cacheable
註解來緩存,cacheNames
爲緩存名稱(必填),cacheManager
、keyGenerator
用我們剛纔在 RedisConfig.java
中配置的。
// 確實可以緩存, @Cache* 註解使用詳解:http://blog.didispace.com/springbootcache1/
@Cacheable(cacheNames = {"users"}, cacheManager = "redisCacheManager", keyGenerator = "redisCacheKeyGenerator")
public User getUser(Long id) {
return userMapper.selectByPrimaryKey(id);
}
package com.blog.www;
import com.blog.www.base.BaseApplicationTests;
import com.blog.www.domain.entity.User;
import com.blog.www.service.UserService;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
/**
* Redis 緩存測試
* <p>
* 創建人:leigq <br>
* 創建時間:2018-12-08 14:48 <br>
* <p>
* 修改人: <br>
* 修改時間: <br>
* 修改備註: <br>
* </p>
*/
public class RedisCacheTest extends BaseApplicationTests {
@Autowired
private CacheManager cacheManager;
@Autowired
private UserService userService;
/**
* 用戶緩存測試
*/
@Test
public void cacheUserTest() {
// 可根據cacheManager查看具體使用哪種緩存
log.warn(cacheManager.getCache("user").getName());
User user1 = userService.getUser(1L);
User user2 = userService.getUser(1L);
User user3 = userService.getUser(1L);
log.warn("user1 is [{}]", user1);
log.warn("user2 is [{}]", user2);
log.warn("user3 is [{}]", user3);
}
}
BaseApplicationTests.java
package com.blog.www.base;
import org.junit.After;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
/**
* 測試基類,其他類繼承此類
* <br/>
* @author :leigq
* @date :2019/8/13 17:17
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public abstract class BaseApplicationTests {
protected Logger log = LoggerFactory.getLogger(this.getClass());
private Long time;
@Before
public void setUp() {
this.time = System.currentTimeMillis();
log.info("==> 測試開始執行 <==");
}
@After
public void tearDown() {
log.info("==> 測試執行完成,耗時:{} ms <==", System.currentTimeMillis() - this.time);
}
}
測試結果如下:
我的項目是使用 MyBatis
並且打開了SQL執行日誌打印,可以看到,第一次查詢打印了SQL,第2、3次的時候沒打印,說明第2、3次直接走的緩存。
常用註解
註解使用詳解:http://blog.didispace.com/springbootcache1/