最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot_Cache自定義使用SimpleCacheManager方式

 更新時(shí)間:2023年07月27日 10:59:55   作者:恐龍弟旺仔  
這篇文章主要介紹了SpringBoot_Cache自定義使用SimpleCacheManager方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

SpringBoot_Cache自定義使用SimpleCacheManager

在SpringBoot_Cache中,會(huì)默認(rèn)使用SimpleCacheManager。

但是筆者遇到一個(gè)問(wèn)題,就是當(dāng)前項(xiàng)目中也引用了redis的maven依賴(lài),導(dǎo)致Cache使用了JedisManager,筆者還是想使用默認(rèn)的SimpleCacheManager

這個(gè)時(shí)候就需要我們手動(dòng)生成SimpleCacheManager的bean,則Cache會(huì)強(qiáng)制使用該bean

關(guān)于SpringBoot_Cache的使用筆者就不再贅述,讀者可參考網(wǎng)絡(luò)文章。

解決方案

創(chuàng)建一個(gè)Config類(lèi),然后主動(dòng)生成SimpleCacheManager,代碼如下

@Configuration
public class CacheManagerConfig {
	@Bean("cacheManager")
	// List<Cache>會(huì)主動(dòng)搜索Cache的實(shí)現(xiàn)bean,并添加到caches中
	public SimpleCacheManager cacheManager(List<Cache> caches){
		SimpleCacheManager simpleCacheManager = new SimpleCacheManager();
		simpleCacheManager.setCaches(caches);
		return simpleCacheManager;
	}
	@Bean("stockDetail")
	public ConcurrentMapCacheFactoryBean stockDetail(){
		ConcurrentMapCacheFactoryBean stockDetail = new ConcurrentMapCacheFactoryBean();
		// 如果用戶(hù)設(shè)置名稱(chēng)為stockDetail的緩存,則需要添加這樣的一個(gè)bean
		stockDetail.setName("stockDetail");
		return stockDetail;
	}
	@Bean("detailMsg")
	public ConcurrentMapCacheFactoryBean detailMsg(){
		ConcurrentMapCacheFactoryBean stockDetail = new ConcurrentMapCacheFactoryBean();
		// 如果用戶(hù)設(shè)置名稱(chēng)為detailMsg的緩存,則需要添加這樣的一個(gè)bean
		stockDetail.setName("detailMsg");
		return stockDetail;
	}
}

注意:如果讀者在使用@Cache的時(shí)候,需要多個(gè)不同命名的cache時(shí),需添加多個(gè)ConcurrentMapCacheFactoryBean

spring cache自定義spring cacheManager和cache

緩存 可以提高訪問(wèn)速度,對(duì)高性能、高并發(fā)有一定的治療效果。

緩存從存儲(chǔ)位置可以分為 JVM級(jí)別緩存,進(jìn)程級(jí)別緩存。JVM級(jí)別緩存優(yōu)點(diǎn):訪問(wèn)速度最快;缺點(diǎn):不能實(shí)現(xiàn)分布式緩存,因?yàn)槊總€(gè)節(jié)點(diǎn)都是一個(gè)單獨(dú)的JVM實(shí)例,所以各個(gè)節(jié)點(diǎn)的緩存不可見(jiàn),會(huì)導(dǎo)致緩存不一致。進(jìn)程級(jí)別緩存優(yōu)點(diǎn):保證緩存一致性,因?yàn)檫M(jìn)程級(jí)別的緩存 相當(dāng)于一個(gè)緩存服務(wù)器,各個(gè)節(jié)點(diǎn)都去同一個(gè)緩存服務(wù)器取數(shù)據(jù),所以緩存一致性有保證。進(jìn)程級(jí)別緩存缺點(diǎn):IO消耗,相對(duì)慢于JVM級(jí)別緩存,但還是比數(shù)據(jù)庫(kù)查詢(xún)快。

Spring 對(duì) cache 進(jìn)行了抽象 并提供注解。但沒(méi)有具體實(shí)現(xiàn)緩存。類(lèi)似于JDBC接口的意思。定義了規(guī)范,讓小面的廠商進(jìn)行具體的實(shí)現(xiàn)。其中定義了兩個(gè)主要的接口:緩存管理器接口:CacheManager  緩存接口:Cache 

緩存管理器接口:CacheManager

接口很簡(jiǎn)單 只有兩個(gè)方法:

public interface CacheManager {
	@Nullable
	Cache getCache(String name);
	Collection<String> getCacheNames();
}

Cache getCache(String name);

此方法可以定義根據(jù)緩存名稱(chēng)獲取緩存,此方法可以實(shí)現(xiàn)二級(jí)緩存。

Collection<String> getCacheNames();

此方法獲取所有緩存名稱(chēng)。

cacheManager是spring獲取cache的入口,所以你可以在getCache(String name) 方法中定義你的獲取cache的實(shí)現(xiàn)邏輯。

public class MyCacheManager implements CacheManager {
	private ConcurrentMap<String, Cache> caches = new ConcurrentHashMap<String, Cache>();
	public MyCacheManager(String name, Cache cache) {
		this.caches.put(name, cache);
	}
	@Override
	public Cache getCache(String name) {
        //更加緩存名字獲取緩存
		Cache cache = this.caches.get(name);
		if (cache != null) {
			return cache;
		} else {
            //如果指定的緩存名字沒(méi)有找到 則新建一個(gè)ConcurrentMapCache 并保存在cachemanager中
			ConcurrentMapCache newCache = new ConcurrentMapCache(name);
			caches.put(name, newCache);
			return newCache;
		}
	}
	@Override
	public Collection<String> getCacheNames() {
		return this.caches.keySet();
	}
}

自定義緩存實(shí)現(xiàn)

spring只是定義了緩存 并實(shí)現(xiàn)了幾個(gè)常用的cache比如目前較為流行的緩存有conCurrentMapCache、ehcache、caffeine。

而redis的實(shí)現(xiàn)由redis廠商提供。

其中conCurrentMapCache由spring實(shí)現(xiàn),在spring-context包中。ehcache、caffeine的實(shí)現(xiàn)放在了spring-context-support包下。

rediscache實(shí)現(xiàn)在 spring-data-redis包下

定義好cacheManager后將其加入spring容器管理。下面貼出緩存在spring配置文件中的配置有些bean是在接下來(lái)講的內(nèi)容。

<bean id="cacheManager" class="com.app.utils.cache.MyCacheManager">
		<constructor-arg value="userCache" /> <!-- 緩存名稱(chēng) -->
		<constructor-arg ref="mapCaffeCache" /> <!-- 緩存實(shí)現(xiàn)類(lèi) -->
	</bean>
	<!-- 自定義緩存實(shí)現(xiàn) -->
	<bean id="mapCaffeCache" class="com.app.utils.cache.MapCaffeCache"></bean>
	<!-- 自定義緩存key實(shí)現(xiàn) -->
	<bean id="cacheKeyGenerator"
		class="com.app.utils.cache.CacheKeyGenerator"></bean>
	<!-- 自定義spring啟動(dòng)加載bean時(shí)加載緩存 -->
	<bean id="cacheBeanPostProcessor"
		class="com.app.CacheBeanPostProcessor"></bean>

配置好bean后 在cache注解中 都會(huì)有cacheManager的指定 比如@cacheable注解 就有cacheManager的指定

@Cacheable(cacheManager = "cacheManager", key = "#i", value = "userCache", condition = "#i>7", unless = "#i>8")
public String getList(int i) {
	return "list server method :: "
		+ LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
}

cache接口

public interface Cache {
	/**
	 * Return the cache name.
	 */
	String getName();
	/**
	 * Return the underlying native cache provider.
	 */
	Object getNativeCache();
	//獲取緩存的主要方法
	@Nullable
	ValueWrapper get(Object key);
	@Nullable
	<T> T get(Object key, @Nullable Class<T> type);
	@Nullable
	<T> T get(Object key, Callable<T> valueLoader);
	//添加緩存的主要方法
	void put(Object key, @Nullable Object value);
	@Nullable
	default ValueWrapper putIfAbsent(Object key, @Nullable Object value) {
		ValueWrapper existingValue = get(key);
		if (existingValue == null) {
			put(key, value);
		}
		return existingValue;
	}
	void evict(Object key);
	default boolean evictIfPresent(Object key) {
		evict(key);
		return false;
	}
	void clear();
	default boolean invalidate() {
		clear();
		return false;
	}
	@FunctionalInterface
	interface ValueWrapper {
		@Nullable
		Object get();
	}
	@SuppressWarnings("serial")
	class ValueRetrievalException extends RuntimeException {
		@Nullable
		private final Object key;
		public ValueRetrievalException(@Nullable Object key, Callable<?> loader, Throwable ex) {
			super(String.format("Value for key '%s' could not be loaded using '%s'", key, loader), ex);
			this.key = key;
		}
		@Nullable
		public Object getKey() {
			return this.key;
		}
	}
}

cache的自定義實(shí)現(xiàn)類(lèi)

public class MapCaffeCache implements Cache {
//	private ConcurrentMapCache mapCache = new ConcurrentMapCache("mapCache");
	private com.github.benmanes.caffeine.cache.@NonNull Cache<Object, Object> mapCache = Caffeine.newBuilder()
			.expireAfterWrite(5, TimeUnit.SECONDS).expireAfterAccess(5, TimeUnit.SECONDS).maximumSize(5).build();
	private com.github.benmanes.caffeine.cache.@NonNull Cache<Object, Object> caffeCache = Caffeine.newBuilder()
			.expireAfterWrite(1, TimeUnit.MINUTES).expireAfterAccess(1, TimeUnit.MINUTES).maximumSize(100).build();
	@Autowired
	private StringRedisTemplate redisTemplate;
	private String name = "userCache";
	@Override
	public String getName() {
		return this.name;
	}
	@Override
	public Object getNativeCache() {
		return this;
	}
	@Override
	public ValueWrapper get(Object key) {
		@Nullable
		Object ob = mapCache.getIfPresent(key);
		// 如果一級(jí)緩存有數(shù)據(jù) 直接返回 不觸發(fā)二級(jí)緩存
		if (ob != null) {
			System.out.println(String.format("Cache L1 (CaffeineCache) :: %s = %s", key, ob));
			SimpleValueWrapper valueWrapper = new SimpleValueWrapper(ob);
			return valueWrapper;
		}
		Object obj = caffeCache.getIfPresent(key);
		if (obj != null) {
			SimpleValueWrapper valueWrapper2 = new SimpleValueWrapper(obj);
			System.out.println(String.format("Cache L2 (CaffeineCache) :: %s = %s", key, obj));
			// 如果二級(jí)緩存有數(shù)據(jù) 則更新到一級(jí)緩存
			mapCache.put(key, obj);
			return valueWrapper2;
		}
		return null;
	}
	@Override
	public <T> T get(Object key, Class<T> type) {
		return (T) get(key).get();
	}
	@Override
	public <T> T get(Object key, Callable<T> valueLoader) {
		return (T) get(key).get();
	}
	@Override
	public void put(Object key, Object value) {
		mapCache.put(key, value);
		caffeCache.put(key, value);
		//當(dāng)nginx搭建集群時(shí) 用redis 訂閱/發(fā)布 功能同步各項(xiàng)目點(diǎn)的緩存一致性
		redisTemplate.convertAndSend("ch1", key + ":>" + value);
	}
	@Override
	public void evict(Object key) {
		mapCache.asMap().remove(key);
		caffeCache.asMap().remove(key);
	}
	@Override
	public void clear() {
		mapCache.asMap().clear();
		caffeCache.asMap().clear();
	}
}

當(dāng)cacheManager和cache實(shí)現(xiàn)完成后就是具體的cache注解使用了。主要有@Cacheable @Cacheput @CacheEvict @Caching @CacheConfig。主要講下@cacheable 其他注解設(shè)置都基本差不多。

@Cacheable用于獲取緩存數(shù)據(jù),如果緩存沒(méi)有命中則執(zhí)行被注解的方法 一般是執(zhí)行數(shù)據(jù)庫(kù)查詢(xún),并剛數(shù)據(jù)庫(kù)查詢(xún)結(jié)果放入緩存中,cacheable緩存注解主要有一下設(shè)置:

@Cacheable(cacheManager = "cacheManager", key = "#i", value = "userCache", condition = "#i>7", unless = "#i>8")
  • cacheManager :設(shè)置緩存管理器 相當(dāng)于數(shù)據(jù)庫(kù)中的庫(kù)名稱(chēng)
  • value : 設(shè)置緩存名稱(chēng) 相當(dāng)于數(shù)據(jù)庫(kù)中的表
  • key:設(shè)置緩存鍵名稱(chēng) 緩存是一個(gè)key value存儲(chǔ)方式 所以可以是查找用的
  • condition :設(shè)置滿(mǎn)足條件 true則緩存 false不緩存
  • unless:設(shè)置不緩存條件 true不緩存 false 緩存

key的設(shè)置規(guī)則 

  • key = " 'key-name' " 寫(xiě)死一個(gè)key 即 key-name 就是key的名字。注意要用單引號(hào)
  • key="#id" 使用注解的方法中的參數(shù) id 的值作為key ,id 是方法參數(shù)列表的名字
  • key="cacheKeyGenerator" cacheKeyGenerator為spring容器管理的自定義key生成器

自定義key生成器

實(shí)現(xiàn)KeyGenerator接口就可以自定義一個(gè)key生成方法

public class CacheKeyGenerator implements KeyGenerator {
	@Override
	public Object generate(Object target, Method method, Object... params) {
		if (params.length == 0) {
			return "spring:cache:defaultKey";
		} else {
			return target.getClass().getSimpleName() + ":" + method.getName();
		}
	}
}

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • java多線程批量拆分List導(dǎo)入數(shù)據(jù)庫(kù)的實(shí)現(xiàn)過(guò)程

    java多線程批量拆分List導(dǎo)入數(shù)據(jù)庫(kù)的實(shí)現(xiàn)過(guò)程

    這篇文章主要給大家介紹了關(guān)于java多線程批量拆分List導(dǎo)入數(shù)據(jù)庫(kù)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2021-10-10
  • Java縮小文件內(nèi)存占用的方法技巧分享

    Java縮小文件內(nèi)存占用的方法技巧分享

    在Java應(yīng)用程序中,處理大文件時(shí)經(jīng)常會(huì)遇到內(nèi)存占用過(guò)高的問(wèn)題,為了縮小文件的內(nèi)存占用,我們可以采取一些有效的方法來(lái)優(yōu)化和管理內(nèi)存的使用,本文將介紹一些在Java中縮小文件內(nèi)存占用的技巧,需要的朋友可以參考下
    2024-10-10
  • SpringBoot3.x整合Nacos和Redis全過(guò)程

    SpringBoot3.x整合Nacos和Redis全過(guò)程

    本文詳細(xì)介紹了使用IntelliJ IDEA創(chuàng)建Spring Boot項(xiàng)目并配置Nacos、Redis和日期類(lèi)LocalDateTime的步驟,還展示了如何使用Docker安裝Nacos并進(jìn)行基本的測(cè)試
    2025-12-12
  • springSecurity使用實(shí)戰(zhàn)指南

    springSecurity使用實(shí)戰(zhàn)指南

    本文系統(tǒng)講解了Spring Security的核心功能,包括實(shí)戰(zhàn)舉例,本文結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧
    2025-08-08
  • javaWeb實(shí)現(xiàn)簡(jiǎn)單文件上傳

    javaWeb實(shí)現(xiàn)簡(jiǎn)單文件上傳

    這篇文章主要為大家詳細(xì)介紹了JAVAWeb實(shí)現(xiàn)簡(jiǎn)單文件上傳,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-06-06
  • springmvc前臺(tái)向后臺(tái)傳值幾種方式總結(jié)(從簡(jiǎn)單到復(fù)雜)

    springmvc前臺(tái)向后臺(tái)傳值幾種方式總結(jié)(從簡(jiǎn)單到復(fù)雜)

    今天小編就為大家分享一篇springmvc前臺(tái)向后臺(tái)傳值幾種方式總結(jié)(從簡(jiǎn)單到復(fù)雜),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-08-08
  • java中的key接口解析

    java中的key接口解析

    這篇文章主要介紹了java中的key接口,有需要的朋友可以參考一下
    2014-01-01
  • Java實(shí)現(xiàn)PDF中文文本查找與高亮的四種方法

    Java實(shí)現(xiàn)PDF中文文本查找與高亮的四種方法

    在實(shí)際開(kāi)發(fā)中,PDF文檔幾乎無(wú)處不在,在處理這些文檔時(shí),常常需要對(duì)文本進(jìn)行搜索和高亮,本文將通過(guò)四個(gè)示例詳細(xì)介紹如何在 Java 中實(shí)現(xiàn) PDF 中文文本的查找與高亮操作,感興趣的小伙伴可以了解下
    2026-05-05
  • 在SpringBoot中該如何配置攔截器

    在SpringBoot中該如何配置攔截器

    今天給大家?guī)?lái)的是關(guān)于SpringBoot的相關(guān)知識(shí),文章圍繞在SpringBoot中該如何配置攔截器展開(kāi),文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下
    2021-06-06
  • java計(jì)算任意位水仙花數(shù)示例(回文數(shù))

    java計(jì)算任意位水仙花數(shù)示例(回文數(shù))

    這篇文章主要介紹了java計(jì)算任意位水仙花數(shù)示例(回文數(shù)),需要的朋友可以參考下
    2014-05-05

最新評(píng)論

博兴县| 紫云| 龙川县| 和龙市| 眉山市| 重庆市| 和政县| 峨边| 华池县| 平安县| 聂拉木县| 阳春市| 佳木斯市| 新和县| 古浪县| 姚安县| 新乡市| 凌海市| 昌宁县| 新丰县| 灵丘县| 阳谷县| 秦安县| 扎赉特旗| 观塘区| 淄博市| 河池市| 交城县| 仲巴县| 林州市| 临高县| 光泽县| 彭州市| 独山县| 宕昌县| 特克斯县| 应用必备| 广水市| 巴塘县| 米林县| 伊金霍洛旗|