SpringBoot同時集成Guava和Redis做爲緩存

參考網頁

http://tramp.cincout.cn/2017/10/31/spring-boot-2017-10-31-spring-boot-multi-cache-manager/java

爲何要混用緩存(本地緩存和分佈式緩存)?

這個要看項目實際須要。一種場景就是有部分數據只是各個服務實例本身須要,因此用本地緩存(如Guava、EhCache)便可,這樣也方便簡潔;而同時有的數據須要各個服務實例共享,這種數據就適合存儲於分佈式緩存中(如Redis)。web

代碼結構圖

要點1-POM--標黃色部分在SpringBoot中引入了Redis和Guava

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

<modelVersion>4.0.0</modelVersion>

<groupId>com.ding.data</groupId>

<artifactId>serverlCacheCase</artifactId>

<version>0.0.1-SNAPSHOT</version>


<properties>

<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

<boot.version>1.3.5.RELEASE</boot.version>

</properties>


<dependencies>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-web</artifactId>

<version>${boot.version}</version>

</dependency>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-test</artifactId>

<version>${boot.version}</version>

<scope>test</scope>

</dependency>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-cache</artifactId>

<version>${boot.version}</version>

</dependency>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-redis</artifactId>

<version>${boot.version}</version>

</dependency>

<dependency> 

<groupId>com.google.guava</groupId> 

<artifactId>guava</artifactId> 

<version>19.0</version> 

</dependency>

</dependencies>

</project>

要點2-application.yml

   

spring:

      #cache:

        #緩存名稱

        #cache-names: guavaDemo

        #緩存最大數量500條, 緩存失效時間 6個小時

        #guava.spec: maximumSize=500,expireAfterWrite=360m

      # REDIS (RedisProperties)  

      redis :

        host : localhost # server host  

        port : 6379 # connection port  

        password : 123

        pool.max-idle : 8 # pool settings ...  

        pool.min-idle : 1

        pool.max-active : 8  

        pool.max-wait : -1

★要點3--配置類

package com.ding.data.config;


import java.util.ArrayList;

import java.util.Arrays;

import java.util.List;

import java.util.concurrent.TimeUnit;


import javax.annotation.Resource;


import org.springframework.boot.ApplicationArguments;

import org.springframework.boot.ApplicationRunner;

import org.springframework.cache.CacheManager;

import org.springframework.cache.guava.GuavaCacheManager;

import org.springframework.cache.support.CompositeCacheManager;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.context.annotation.Primary;

import org.springframework.data.redis.cache.RedisCacheManager;

import org.springframework.data.redis.core.RedisTemplate;

import org.springframework.data.redis.serializer.StringRedisSerializer;


import com.google.common.cache.CacheBuilder;

import com.google.common.collect.Lists;


@Configuration

public class CacheConfig implements ApplicationRunner {

@Resource

private List<CacheManager> cacheManagers;


public void run(ApplicationArguments args) throws Exception {

System.out.println("CacheManager大小爲=========" + cacheManagers.size());

System.out.println("=================================================");

for(CacheManager c:cacheManagers){

System.out.println(c.getCacheNames());

}

}


@Bean(name = "redisCacheManager")

public RedisCacheManager redisCacheManager(

RedisTemplate<Object, Object> redisTemplate) {

redisTemplate.setKeySerializer(new StringRedisSerializer());

RedisCacheManager redisCacheManager = new RedisCacheManager(

redisTemplate);

redisCacheManager.setCacheNames(Arrays.asList("redisDemo"));

redisCacheManager.setUsePrefix(true);

return redisCacheManager;

}


@Bean(name = "guavaCacheManager")

public GuavaCacheManager getGuavaCacheManager() {

GuavaCacheManager guavaCacheManager = new GuavaCacheManager();

guavaCacheManager.setCacheBuilder(CacheBuilder.newBuilder()

.expireAfterWrite(3600, TimeUnit.SECONDS).maximumSize(1000));

ArrayList<String> guavaCacheNames = Lists.newArrayList();

guavaCacheNames.add("guavaDemo");

guavaCacheManager.setCacheNames(guavaCacheNames);

return guavaCacheManager;

}


@Bean(name = "cacheManager")

@Primary

public CompositeCacheManager cacheManager(

RedisCacheManager redisCacheManager,

GuavaCacheManager guavaCacheManager) {

CompositeCacheManager cacheManager = new CompositeCacheManager(

redisCacheManager, guavaCacheManager);

return cacheManager;

}

}

要點4--guava緩存

package com.ding.data.cache;


import java.text.SimpleDateFormat;

import java.util.Date;

import java.util.HashMap;

import java.util.Map;


import javax.annotation.PostConstruct;


import org.springframework.cache.annotation.CacheEvict;

import org.springframework.cache.annotation.CachePut;

import org.springframework.cache.annotation.Cacheable;

import org.springframework.stereotype.Service;


@Service

//@CacheConfig(cacheManager = "guavaCacheManager")

public class GuavaDataCache {


private Map<Long, String> dataMap = new HashMap<Long, String>();


/**

 * 初始化

 */

@PostConstruct

public void init() {

dataMap.put(1L, "張三");

dataMap.put(2L, "李四");

dataMap.put(3L, "王五");

}


/**

 * 查詢

 * 若是數據沒有緩存,那麼從dataMap裏面獲取,若是緩存了,

 * 那麼從guavaDemo裏面獲取

 * 而且將緩存的數據存入到 guavaDemo裏面

 * 其中key 爲 #id+dataMap

 */

@Cacheable(value="guavaDemo" ,key="#id + 'dataMap'")

public String query(Long id) {

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

System.out.println(sdf.format(new Date()) + " : query id is " + id);

return dataMap.get(id);

}


/**

 * 插入 或者更新

 * 插入或更新數據到dataMap中

 * 而且緩存到 guavaDemo中

 * 若是存在了那麼更新緩存中的值

 * 其中key 爲 #id+dataMap

 */

@CachePut(value="guavaDemo" ,key="#id + 'dataMap'")

public String put(Long id, String value) {

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

System.out.println(sdf.format(new Date()) + " : add data ,id is "+ id);

dataMap.put(id, value);

// data persistence

return value;

}


/**

 * 刪除

 * 刪除dataMap裏面的數據

 * 而且刪除緩存guavaDemo中的數據

 * 其中key 爲 #id+dataMap

 */

@CacheEvict(value="guavaDemo" , key="#id + 'dataMap'")

public void remove(Long id) {

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

System.out.println(sdf.format(new Date()) + " : remove id is "+ id + " data");

dataMap.remove(id);

// data remove  

}


}

要點5--redis緩存

package com.ding.data.cache;


import java.text.SimpleDateFormat;

import java.util.Date;

import java.util.HashMap;

import java.util.Map;


import javax.annotation.PostConstruct;


import org.springframework.cache.annotation.CacheEvict;

import org.springframework.cache.annotation.CachePut;

import org.springframework.cache.annotation.Cacheable;

import org.springframework.stereotype.Service;


@Service

//@CacheConfig(cacheManager = "redisCacheManager")

public class RedisDataCache {


private Map<Long, String> dataMap = new HashMap<Long, String>();


/**

 * 初始化

 */

@PostConstruct

public void init() {

dataMap.put(1L, "111");

dataMap.put(2L, "222");

dataMap.put(3L, "333");

}


/**

 * 查詢

 * 若是數據沒有緩存,那麼從dataMap裏面獲取,若是緩存了,

 * 那麼從guavaDemo裏面獲取

 * 而且將緩存的數據存入到 guavaDemo裏面

 * 其中key 爲 #id+dataMap

 */

@Cacheable(value="redisDemo" ,key="#id + 'dataMap'")

public String query(Long id) {

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

System.out.println(sdf.format(new Date()) + " : query id is " + id);

return dataMap.get(id);

}


/**

 * 插入 或者更新

 * 插入或更新數據到dataMap中

 * 而且緩存到 guavaDemo中

 * 若是存在了那麼更新緩存中的值

 * 其中key 爲 #id+dataMap

 */

@CachePut(value="redisDemo" ,key="#id + 'dataMap'")

public String put(Long id, String value) {

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

System.out.println(sdf.format(new Date()) + " : add data ,id is "+ id);

dataMap.put(id, value);

// data persistence

return value;

}


/**

 * 刪除

 * 刪除dataMap裏面的數據

 * 而且刪除緩存guavaDemo中的數據

 * 其中key 爲 #id+dataMap

 */

@CacheEvict(value="redisDemo" , key="#id + 'dataMap'")

public void remove(Long id) {

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

System.out.println(sdf.format(new Date()) + " : remove id is "+ id + " data");

dataMap.remove(id);

// data remove  

}


}

要點6--調用

package com.ding.data;


import java.text.SimpleDateFormat;

import java.util.Date;


import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.cache.annotation.EnableCaching;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;


import com.ding.data.cache.GuavaDataCache;

import com.ding.data.cache.RedisDataCache;


/**

 * 是Spring Boot項目的核心註解,主要是開啓自動配置

 */

@SpringBootApplication

// same as @Configuration @EnableAutoConfiguration @ComponentScan

@RestController

// 開啓緩存

@EnableCaching

public class App {


@Autowired

private GuavaDataCache dataCache;


@Autowired

private RedisDataCache rdataCache;


public static void main(String[] args) {

SpringApplication.run(App.class, args);

}


@RequestMapping("/put")

public String put(Long id, String value) {

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

return sdf.format(new Date()) + " : value is "

+ dataCache.put(id, value);

}


@RequestMapping("/get")

public String query(Long id) {

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

return sdf.format(new Date()) + " : value is " + dataCache.query(id);

}


@RequestMapping("/remove")

public String remove(Long id) {

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

dataCache.remove(id);

return sdf.format(new Date()) + " : success ";

}


@RequestMapping("/putr")

public String putr(Long id, String value) {

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

return sdf.format(new Date()) + " : value is "

+ rdataCache.put(id, value);

}


@RequestMapping("/getr")

public String queryr(Long id) {

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

return sdf.format(new Date()) + " : value is " + rdataCache.query(id);

}


@RequestMapping("/remover")

public String remover(Long id) {

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

rdataCache.remove(id);

return sdf.format(new Date()) + " : success ";

}


}

測試1--redis中是否有寫入--有的

RedisCache訪問

訪問redis

http://localhost:8080/getr?id=1spring

查看Redis服務器中,以下apache

可見緩存

/getr?id=1服務器

這個連接返回時將數據寫入了Redis服務器中。app

RedisCache寫入

訪問maven

http://localhost:8080/putr?id=1&value=999999分佈式

而後查看Redis服務器,以下圖

測試2--guava緩存的訪問

訪問

http://localhost:8080/get?id=1

而後調用

http://localhost:8080/put?id=1&value=777777

查看Redis中的值,並未發生任何改變。說明redis緩存和guava緩存互不干擾,都按照設想的進行了正確的訪問。爲何這麼說?由於以前試過別的配置,結果發現緩存發生了混亂,而如今正常,說明如今的配置類文件和相關的配置信息都寫正確了。

★要點3講解

項目啓動過程當中打印

項目啓動過程當中打印以下。ApplicationRunner接口的具體用法能夠自行百度。實現ApplicationRunner接口並非必須的,這裏就是爲了啓動時打印展現CacheManager。

從圖中能夠看到被 @Bean 註解的三個CachaManager都加進了 cacheManagers 中。

CompositeCacheManager

Spring Cache在 CacheManager 之下能夠採用緩存名稱(cacheNames 屬性)來對緩存進行區分。Spring Cache 提供了CompositeCacheManager 來對全部的 CacheManager 進行代理。根據指定的cacheName 去遍歷全部的 CacheManager,查找對應的緩存。

相關文章
相關標籤/搜索