SpringBoot同時集成Redis和Guava做爲緩存組件--進一步分析代碼

請先看

https://my.oschina.net/u/3866531/blog/1840386java

CompositeCacheManager

Composite,混合的,混成的

Spring提供CompositeCacheManager的主要目的就是爲了混合使用多種緩存時進行管理。redis

1、實際測試--CompositeCacheManager中打斷點

斷點打在getCache上

GuavaDataCache源碼--去掉類上的@CacheConfig(cacheManager = "guavaCacheManager")註解

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  

}


}

RedisDataCache源碼--去掉類上的@CacheConfig(cacheManager = "redisCacheManager")註解

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  

}

}

訪問http://localhost:8080/get?id=1,進入斷點,看到以下

訪問http://localhost:8080/getr?id=1,進入斷點,看到以下

因此可見此時是經過CompositeCacheManager進行管理的,CacheConfig類中的CompositeCacheManager 起做用了

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;

}

}
  • 2、實際測試--CompositeCacheManager中打斷點

斷點打在getCache上

GuavaDataCache源碼--加上類上的@CacheConfig(cacheManager = "guavaCacheManager")註解

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  

}


}

RedisDataCache源碼--去掉類上的@CacheConfig(cacheManager = "redisCacheManager")註解

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  

}

}

訪問http://localhost:8080/get?id=1,沒進入斷點

訪問http://localhost:8080/getr?id=1,沒進入斷點

因此可見,此時由於標註上了 @CacheConfig(cacheManager = "guavaCacheManager") 和 @CacheConfig(cacheManager = "redisCacheManager") ,因此直接就知道須要用哪一個CacheManager了,不須要CompositeCacheManager去匹配了

直接去掉CacheConfig類中的CompositeCacheManager ,在不一樣的緩存上加上 @CacheConfig(cacheManager = "guavaCacheManager") 和 @CacheConfig(cacheManager = "redisCacheManager"),是否能夠?——測試一下

此時的CacheConfig類代碼

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.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

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;

// }

}

結果啓動時就報錯了

java.lang.IllegalStateException: No CacheResolver specified, and no unique bean of type CacheManager found. Mark one as primary (or give it the name 'cacheManager') or declare a specific CacheManager to use, that serves as the default one.spring

at org.springframework.cache.interceptor.CacheAspectSupport.afterSingletonsInstantiated(CacheAspectSupport.java:186) ~[spring-context-4.2.6.RELEASE.jar:4.2.6.RELEASE]緩存

at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:792) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE]spring-boot

at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:839) ~[spring-context-4.2.6.RELEASE.jar:4.2.6.RELEASE]測試

at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:538) ~[spring-context-4.2.6.RELEASE.jar:4.2.6.RELEASE]ui

at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:118) ~[spring-boot-1.3.5.RELEASE.jar:1.3.5.RELEASE]google

at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:766) [spring-boot-1.3.5.RELEASE.jar:1.3.5.RELEASE]spa

at org.springframework.boot.SpringApplication.createAndRefreshContext(SpringApplication.java:361) [spring-boot-1.3.5.RELEASE.jar:1.3.5.RELEASE].net

at org.springframework.boot.SpringApplication.run(SpringApplication.java:307) [spring-boot-1.3.5.RELEASE.jar:1.3.5.RELEASE]

at org.springframework.boot.SpringApplication.run(SpringApplication.java:1191) [spring-boot-1.3.5.RELEASE.jar:1.3.5.RELEASE]

at org.springframework.boot.SpringApplication.run(SpringApplication.java:1180) [spring-boot-1.3.5.RELEASE.jar:1.3.5.RELEASE]

at com.ding.data.App.main(App.java:33) [classes/:na]

上面報錯是由於Spring Context 中存在多個實現了 CacheManager.class 的 Bean,須要使用 @Primary 註解指定優先選擇的 CacheManager

那麼指定 GuavaCacheManager 爲 @Primary,此時的CacheConfig類代碼

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.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")

@Primary

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;

// }

}

正常啓動,剛纔的報錯消失

測試,一切正常

因此不須要使用CompositeCacheManager類,在使用緩存的地方經過 @CacheConfig 指定CacheManager,就能夠混合使用多種緩存組件了。同時,要記得在配置類中指定一個 @Primary 緩存

相關文章
相關標籤/搜索