本文介紹spring boot項目集成redis緩存的過程。java
redis是一個開源的內存NOSQL數據庫,在web開發中主要被用於數據緩存。通常在高併發的狀況下,web服務器接受訪問時,直接從數據庫加載是慢的,須要把經常使用數據緩存到redis中,提升加載速度和併發能力。mysql
建立一個spring boot項目,配置redis各相關 bean,實現幾個接口,經過兩種方式測試redis緩存:linux
如沒有開發環境,可參考前面章節:[spring boot 開發環境搭建(Eclipse)]。git
打開Eclipse,建立spring boot的spring starter project項目,選擇菜單:File > New > Project ...
,彈出對話框,選擇:Spring Boot > Spring Starter Project
,在配置依賴時,勾選web
、redis
,完成項目建立。github
須要用到commons-pool2
庫,在pom.xml
中添加依賴web
<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> </dependency>
在application.properties
文件中配置redis服務器的鏈接redis
## REDIS (RedisProperties) # Redis數據庫索引(默認爲0) spring.redis.database=0 # Redis服務器地址 spring.redis.host=192.168.0.99 # Redis服務器鏈接端口 spring.redis.port=6379 # Redis服務器鏈接密碼(默認爲空) spring.redis.password= # 鏈接池最大鏈接數(使用負值表示沒有限制) spring.redis.lettuce.pool.max-active=8 # 鏈接池最大阻塞等待時間(使用負值表示沒有限制) spring.redis.lettuce.pool.max-wait=-1 # 鏈接池中的最大空閒鏈接 spring.redis.lettuce.pool.max-idle=8 # 鏈接池中的最小空閒鏈接 spring.redis.lettuce.pool.min-idle=0
項目目錄結構以下圖,咱們添加了幾個類,下面將詳細介紹。spring
首先使用@EnableCaching
開啓以註解方式使用緩存。sql
而後配置redis相關的bean數據庫
/** * @description redis配置 配置序列化方式以及緩存管理器 */ @EnableCaching // 開啓緩存 @Configuration @AutoConfigureAfter(RedisAutoConfiguration.class) public class RedisConfig { /** * 配置自定義redisTemplate * * @param connectionFactory * @return */ @Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) { RedisTemplate<String, Object> template = new RedisTemplate<>(); template.setConnectionFactory(connectionFactory); template.setValueSerializer(jackson2JsonRedisSerializer()); //使用StringRedisSerializer來序列化和反序列化redis的key值 template.setKeySerializer(new StringRedisSerializer()); template.setHashKeySerializer(new StringRedisSerializer()); template.setHashValueSerializer(jackson2JsonRedisSerializer()); template.afterPropertiesSet(); return template; } /** * json序列化 * @return */ @Bean public RedisSerializer<Object> jackson2JsonRedisSerializer() { //使用Jackson2JsonRedisSerializer來序列化和反序列化redis的value值 Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<Object>(Object.class); ObjectMapper mapper = new ObjectMapper(); mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); serializer.setObjectMapper(mapper); return serializer; } /** * 配置緩存管理器 * @param redisConnectionFactory * @return */ @Bean public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) { // 生成一個默認配置,經過config對象便可對緩存進行自定義配置 RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig(); // 設置緩存的默認過時時間,也是使用Duration設置 config = config.entryTtl(Duration.ofMinutes(1)) // 設置 key爲string序列化 .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())) // 設置value爲json序列化 .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer())) // 不緩存空值 .disableCachingNullValues(); // 設置一個初始化的緩存空間set集合 Set<String> cacheNames = new HashSet<>(); cacheNames.add("timeGroup"); cacheNames.add("user"); // 對每一個緩存空間應用不一樣的配置 Map<String, RedisCacheConfiguration> configMap = new HashMap<>(); configMap.put("timeGroup", config); configMap.put("user", config.entryTtl(Duration.ofSeconds(120))); // 使用自定義的緩存配置初始化一個cacheManager RedisCacheManager cacheManager = RedisCacheManager.builder(redisConnectionFactory) // 必定要先調用該方法設置初始化的緩存名,再初始化相關的配置 .initialCacheNames(cacheNames) .withInitialCacheConfigurations(configMap) .build(); return cacheManager; } /** * 緩存的key是 包名+方法名+參數列表 */ @Bean public KeyGenerator keyGenerator() { return (target, method, objects) -> { StringBuilder sb = new StringBuilder(); sb.append(target.getClass().getName()); sb.append("::" + method.getName() + ":"); for (Object obj : objects) { sb.append(obj.toString()); } return sb.toString(); }; } }
public class User { private long id; private String nickname; private String mobile; @JsonProperty(access = Access.WRITE_ONLY) //在輸出的Json數據中隱藏密碼,只能輸入不輸出 private String password; private String role; public User(long id, String nickname, String mobile, String password, String role) { this.id = id; this.nickname = nickname; this.mobile = mobile; this.password = password; this.role = role; } public User() { super(); } public String getNickname() { return nickname; } public void setNickname(String nickname) { this.nickname = nickname; } public long getId() { return id; } public void setId(long id) { this.id = id; } public String getMobile() { return mobile; } public void setMobile(String mobile) { this.mobile = mobile; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getRole() { return role; } public void setRole(String role) { this.role = role; } }
@Cacheable
- 代表對應方法的返回結果能夠被緩存,首次調用後,下次就從緩存中讀取結果,方法不會再被執行了。@CachePut
- 更新緩存,方法每次都會執行@CacheEvict
- 清除緩存,方法每次都會執行由於主要的業務邏輯在服務層實現,通常會把緩存註解加在服務層的方法上。
下面幾個服務層的方法會加緩存註解:
@Cacheable
@CacheEvict
UserSevice.java 接口
public interface UserService { public User getUserById(long userId); public User updateUserNickname(long userId, String nickname); }
UserServiceImpl.java 實現類
@Service("userService") public class UserServiceImpl implements UserService { private static final org.slf4j.Logger log = LoggerFactory.getLogger(UserServiceImpl.class); private User user = new User(1l, "abc1", "13512345678", "123456", "role-user"); @Cacheable(value = "user", key= "#userId") @Override public User getUserById(long userId) { log.info("加載用戶信息"); return user; } @CacheEvict(value = "user", key= "#userId") @Override public User updateUserNickname(long userId, String nickname) { user.setNickname(nickname); return user; } }
@RestController @EnableAutoConfiguration @RequestMapping("/user") public class UserController { // 注入service類 @Resource private UserService userService; // 注入RedisTemplate @Resource private RedisTemplate<String, Object> redis; // 讀取用戶信息,測試緩存使用:除了首次讀取,接下來都應該從緩存中讀取 @RequestMapping(value="{id}", method=RequestMethod.GET, produces="application/json") public User getUser(@PathVariable long id) throws Exception { User user = this.userService.getUserById(id); return user; } // 修改用戶信息,測試刪除緩存 @RequestMapping(value = "/{id}/change-nick", method = RequestMethod.POST, produces="application/json") public User changeNickname(@PathVariable long id) throws Exception{ String nick = "abc-" + Math.random(); User user = this.userService.updateUserNickname(id, nick); return user; } // 使用RedisTemplate訪問redis服務器 @RequestMapping(value="/redis", method=RequestMethod.GET, produces="application/json") public String redis() throws Exception { // 設置鍵"project-name",值"qikegu-springboot-redis-demo" redis.opsForValue().set("project-name", "qikegu-springboot-redis-demo"); String value = (String) redis.opsForValue().get("project-name"); return value; } }
Eclipse左側,在項目根目錄上點擊鼠標右鍵彈出菜單,選擇:run as -> spring boot app
運行程序。 打開Postman訪問接口,
同時監控redis服務器。
監控redis服務器,使用
redis-cli
命令連上服務器,而後使用monitor
命令開始監控:
運行結果以下:
獲取用戶信息
redis中的數據,能夠看到數據經過SET
指令保存進redis了
屢次獲取用戶信息,能夠看到經過GET
指令從redis中讀取緩存
修改用戶信息
redis中的緩存被刪除了
測試使用RedisTemplate訪問redis服務器
redis中的數據變化