SpringBoot中整合Redis(緩存篇)
實(shí)際開發(fā)中緩存處理是必須的,不可能我們每次客戶端去請求一次服務(wù)器,服務(wù)器每次都要去數(shù)據(jù)庫中進(jìn)行查找,為什么要使用緩存?說到底是為了提高系統(tǒng)的運(yùn)行速度。將用戶頻繁訪問的內(nèi)容存放在離用戶最近,訪問速度最快的地方,提高用戶的響應(yīng)速度,今天先來講下在springboot中整合redis的詳細(xì)步驟。
一、安裝
redis下載地址:
首先要在本地安裝一個redis程序,安裝過程十分簡單(略過),安裝完成后進(jìn)入到redis文件夾中可以看到如下:
點(diǎn)擊redis-server.exe開啟redis服務(wù),可以看到如下圖所示即代表開啟redis服務(wù)成功:
那么我們可以開啟redis客戶端進(jìn)行測試:
二、整合到springboot
1、在項目中加入redis依賴,pom文件中添加如下:
- <!-- 整合Redis緩存支持 -->
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-data-redis</artifactId>
- </dependency>
2、在application.yml中添加redis配置:
- ##默認(rèn)密碼為空
- redis:
- host: 127.0.0.1
- # Redis服務(wù)器連接端口
- port: 6379
- jedis:
- pool:
- #連接池最大連接數(shù)(使用負(fù)值表示沒有限制)
- max-active: 100
- # 連接池中的最小空閑連接
- max-idle: 10
- # 連接池最大阻塞等待時間(使用負(fù)值表示沒有限制)
- max-wait: 100000
- # 連接超時時間(毫秒)
- timeout: 5000
- #默認(rèn)是索引為0的數(shù)據(jù)庫
- database: 0
3、新建RedisConfiguration配置類,繼承CachingConfigurerSupport,@EnableCaching開啟注解
- @Configuration
- @EnableCaching
- public class RedisConfiguration extends CachingConfigurerSupport {
- /**
- * 自定義生成key的規(guī)則
- */
- @Override
- public KeyGenerator keyGenerator() {
- return new KeyGenerator() {
- @Override
- public Object generate(Object o, Method method, Object... objects) {
- //格式化緩存key字符串
- StringBuilder sb = new StringBuilder();
- //追加類名
- sb.append(o.getClass().getName());
- //追加方法名
- sb.append(method.getName());
- //遍歷參數(shù)并且追加
- for (Object obj : objects) {
- sb.append(obj.toString());
- }
- System.out.println("調(diào)用Redis緩存Key : " + sb.toString());
- return sb.toString();
- }
- };
- }
- /**
- * 采用RedisCacheManager作為緩存管理器
- * @param connectionFactory
- */
- @Bean
- public CacheManager cacheManager(RedisConnectionFactory connectionFactory) {
- RedisCacheManager redisCacheManager = RedisCacheManager.create(connectionFactory);
- return redisCacheManager;
- }
- @Bean
- public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) {
- ////解決鍵、值序列化問題
- StringRedisTemplate template = new StringRedisTemplate(factory);
- 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;
- }
- }
4、創(chuàng)建自定義的接口來定義需要的redis的功能
- /**
- * K 指以hash結(jié)構(gòu)操作時 鍵類型
- * T 為數(shù)據(jù)實(shí)體 應(yīng)實(shí)現(xiàn)序列化接口,并定義serialVersionUID * RedisTemplate 提供了五種數(shù)據(jù)結(jié)構(gòu)操作類型 hash / list / set / zset / value
- * 方法命名格式為 數(shù)據(jù)操作類型 + 操作 如 hashPut 指以hash結(jié)構(gòu)(也就是map)想key添加鍵值對
- */
- public interface RedisHelper<HK, T> {
- /**
- * Hash結(jié)構(gòu) 添加元素 * @param key key * @param hashKey hashKey * @param domain 元素
- */
- void hashPut(String key, HK hashKey, T domain);
- /**
- * Hash結(jié)構(gòu) 獲取指定key所有鍵值對 * @param key * @return
- */
- Map<HK, T> hashFindAll(String key);
- /**
- * Hash結(jié)構(gòu) 獲取單個元素 * @param key * @param hashKey * @return
- */
- T hashGet(String key, HK hashKey);
- void hashRemove(String key, HK hashKey);
- /**
- * List結(jié)構(gòu) 向尾部(Right)添加元素 * @param key * @param domain * @return
- */
- Long listPush(String key, T domain);
- /**
- * List結(jié)構(gòu) 向頭部(Left)添加元素 * @param key * @param domain * @return
- */
- Long listUnshift(String key, T domain);
- /**
- * List結(jié)構(gòu) 獲取所有元素 * @param key * @return
- */
- List<T> listFindAll(String key);
- /**
- * List結(jié)構(gòu) 移除并獲取數(shù)組第一個元素 * @param key * @return
- */
- T listLPop(String key);
- /**
- * 對象的實(shí)體類
- * @param key
- * @param domain
- * @return
- */
- void valuePut(String key, T domain);
- /**
- * 獲取對象實(shí)體類
- * @param key
- * @return
- */
- T getValue(String key);
- void remove(String key);
- /**
- * 設(shè)置過期時間 * @param key 鍵 * @param timeout 時間 * @param timeUnit 時間單位
- */
- boolean expirse(String key, long timeout, TimeUnit timeUnit);
- }
下面是創(chuàng)建RedisHelperImpl進(jìn)行接口的實(shí)現(xiàn)
- @Service("RedisHelper")
- public class RedisHelperImpl<HK, T> implements RedisHelper<HK, T> {
- // 在構(gòu)造器中獲取redisTemplate實(shí)例, key(not hashKey) 默認(rèn)使用String類型
- private RedisTemplate<String, T> redisTemplate;
- // 在構(gòu)造器中通過redisTemplate的工廠方法實(shí)例化操作對象
- private HashOperations<String, HK, T> hashOperations;
- private ListOperations<String, T> listOperations;
- private ZSetOperations<String, T> zSetOperations;
- private SetOperations<String, T> setOperations;
- private ValueOperations<String, T> valueOperations;
- // IDEA雖然報錯,但是依然可以注入成功, 實(shí)例化操作對象后就可以直接調(diào)用方法操作Redis數(shù)據(jù)庫
- @Autowired
- public RedisHelperImpl(RedisTemplate<String, T> redisTemplate) {
- this.redisTemplate = redisTemplate;
- this.hashOperations = redisTemplate.opsForHash();
- this.listOperations = redisTemplate.opsForList();
- this.zSetOperations = redisTemplate.opsForZSet();
- this.setOperations = redisTemplate.opsForSet();
- this.valueOperations = redisTemplate.opsForValue();
- }
- @Override
- public void hashPut(String key, HK hashKey, T domain) {
- hashOperations.put(key, hashKey, domain);
- }
- @Override
- public Map<HK, T> hashFindAll(String key) {
- return hashOperations.entries(key);
- }
- @Override
- public T hashGet(String key, HK hashKey) {
- return hashOperations.get(key, hashKey);
- }
- @Override
- public void hashRemove(String key, HK hashKey) {
- hashOperations.delete(key, hashKey);
- }
- @Override
- public Long listPush(String key, T domain) {
- return listOperations.rightPush(key, domain);
- }
- @Override
- public Long listUnshift(String key, T domain) {
- return listOperations.leftPush(key, domain);
- }
- @Override
- public List<T> listFindAll(String key) {
- if (!redisTemplate.hasKey(key)) {
- return null;
- }
- return listOperations.range(key, 0, listOperations.size(key));
- }
- @Override
- public T listLPop(String key) {
- return listOperations.leftPop(key);
- }
- @Override
- public void valuePut(String key, T domain) {
- valueOperations.set(key, domain);
- }
- @Override
- public T getValue(String key) {
- return valueOperations.get(key);
- }
- @Override
- public void remove(String key) {
- redisTemplate.delete(key);
- }
- @Override
- public boolean expirse(String key, long timeout, TimeUnit timeUnit) {
- return redisTemplate.expire(key, timeout, timeUnit);
- }
- }
三、測試
編寫TestRedis類進(jìn)行測試
- @RunWith(SpringRunner.class)
- @SpringBootTest
- public class TestRedis {
- @Autowired
- private StringRedisTemplate stringRedisTemplate;
- @Autowired
- private RedisTemplate redisTemplate;
- @Autowired
- private RedisHelperImpl redisHelper;
- @Test
- public void test() throws Exception{
- // 基本寫法
- // stringRedisTemplate.opsForValue().set("aaa","111");
- // Assert.assertEquals("111",stringRedisTemplate.opsForValue().get("aaa"));
- // System.out.println(stringRedisTemplate.opsForValue().get("aaa"));
- Author user=new Author();
- user.setName("Alex");
- user.setIntro_l("不會打籃球的程序不是好男人");
- redisHelper.valuePut("aaa",user);
- System.out.println(redisHelper.getValue("aaa"));
- }
- @Test
- public void testObj() throws Exception {
- Author user=new Author();
- user.setName("Jerry");
- user.setIntro_l("不會打籃球的程序不是好男人!");
- ValueOperations<String, Author> operations=redisTemplate.opsForValue();
- operations.set("502", user);
- Thread.sleep(500);
- boolean exists=redisTemplate.hasKey("502");
- if(exists){
- System.out.println(redisTemplate.opsForValue().get("502"));
- }else{
- System.out.println("exists is false");
- }
- // Assert.assertEquals("aa", operations.get("com.neo.f").getUserName());
- }
- }
運(yùn)行TestRedis測試類,結(jié)果如下:
注意:如果在RedisConfiguration中不配置redisTemplate(RedisConnectionFactory factory)注解,會造成鍵、值的一個序列化問題,有興趣的可以去試一下。序列化:序列化框架的選型和比對
四、項目實(shí)戰(zhàn)
首先需要在程序的入口處Application中添加@EnableCaching開啟緩存的注解
- @EnableCaching //開啟緩存
- @SpringBootApplication
- public class PoetryApplication {
- public static void main(String[] args) {
- SpringApplication.run(PoetryApplication.class, args);
- }
- }
上面的redis相關(guān)寫法是我們自定義設(shè)置并獲取的,那么我們經(jīng)常要在訪問接口的地方去使用redis進(jìn)行緩存相關(guān)實(shí)體對象以及集合等,那么我們怎么實(shí)現(xiàn)呢?
比如我現(xiàn)在想在AuthorController中去緩存作者相關(guān)信息的緩存數(shù)據(jù),該怎么辦呢?如下:
- @RestController
- @RequestMapping(value = "/poem")
- public class AuthorController {
- private final static Logger logger = LoggerFactory.getLogger(AuthorController.class);
- @Autowired
- private AuthorRepository authorRepository;
- @Cacheable(value="poemInfo") //自動根據(jù)方法生成緩存
- @PostMapping(value = "/poemInfo")
- public Result<Author> author(@RequestParam("author_id") int author_id, @RequestParam("author_name")String author_name) {
- if(StringUtils.isEmpty(author_id) || StringUtils.isEmpty(author_name)){
- return ResultUtils.error(ResultCode.INVALID_PARAM_EMPTY);
- }
- Author author;
- Optional<Author> optional = authorRepository.getAuthorByIdAndName(author_id, author_name);
- if (optional.isPresent()) {
- author = optional.get();
- //通過\n或者多個空格 進(jìn)行過濾去重
- if (!StringUtils.isEmpty(author.getIntro_l())) {
- String s = author.getIntro_l();
- String intro = s.split("\\s +")[0];
- author.setIntro_l(intro);
- }
- } else {
- return ResultUtils.error(ResultCode.NO_FIND_THINGS);
- }
- return ResultUtils.ok(author);
- }
- }
這里 @Cacheable(value="poemInfo")這個注解的意思就是自動根據(jù)方法生成緩存,value就是緩存下來的key。到這里我們就已經(jīng)把redis整合到了springboot中了