欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot整合Ehcache3的實現(xiàn)步驟

 更新時間:2022年01月04日 15:25:43   作者:code2roc  
本文主要介紹了SpringBoot整合Ehcache3的實現(xiàn)步驟,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下

前言

公司部門老項目要遷移升級java版本,需要進行緩存相關操作,原框架未支持這部分,經(jīng)過調研java相關緩存方案大致分為ehcache和redis兩種,redis的value最大值為500mb且超過1mb會對存取有性能影響,業(yè)務系統(tǒng)需要支持列表查詢緩存就不可避免的涉及到大量的數(shù)據(jù)存取過濾,ehcache支持內存+磁盤緩存不用擔心緩存容量問題,所以框架初步版本決定集成ehcache3,設計流程結構如下圖所示

緩存配置

maven引用

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>
        <dependency>
            <groupId>org.ehcache</groupId>
            <artifactId>ehcache</artifactId>
        </dependency>

個性化配置

  #緩存配置
  cache:
    ehcache:
      heap: 1000
      offheap: 100
      disk: 500
      diskDir: tempfiles/cache/
@Component
@ConfigurationProperties("frmae.cache.ehcache")
public class EhcacheConfiguration {
? ? /**
? ? ?* ehcache heap大小
? ? ?* jvm內存中緩存的key數(shù)量
? ? ?*/
? ? private int heap;
? ? /**
? ? ?* ehcache offheap大小
? ? ?* 堆外內存大小, 單位: MB
? ? ?*/
? ? private int offheap;
? ? /**
? ? ?* 磁盤持久化目錄
? ? ?*/
? ? private String diskDir;
? ? /**
? ? ?* ehcache disk
? ? ?* 持久化到磁盤的大小, 單位: MB
? ? ?* diskDir有效時才生效
? ? ?*/
? ? private int disk;

? ? public EhcacheConfiguration(){
? ? ? ? heap = 1000;
? ? ? ? offheap = 100;
? ? ? ? disk = 500;
? ? ? ? diskDir = "tempfiles/cache/";
? ? }
}

代碼注入配置

因為springboot默認緩存優(yōu)先注入redis配置,所以需要手動聲明bean進行注入,同時ehcache的value值必須支持序列化接口,不能使用Object代替,這里聲明一個緩存基類,所有緩存value對象必須繼承該類

public class BaseSystemObject implements Serializable {
    
}
@Configuration
@EnableCaching
public class EhcacheConfig {
? ? @Autowired
? ? private EhcacheConfiguration ehcacheConfiguration;
? ? @Autowired
? ? private ApplicationContext context;

? ? @Bean(name = "ehCacheManager")
? ? public CacheManager getCacheManager() {
? ? ? ? //資源池生成器配置持久化
? ? ? ? ResourcePoolsBuilder resourcePoolsBuilder = ?? ??? ??? ??? ? ?ResourcePoolsBuilder.newResourcePoolsBuilder()
? ? ? ? ? ? ? ? // 堆內緩存大小
? ? ? ? ? ? ? ? .heap(ehcacheConfiguration.getHeap(), EntryUnit.ENTRIES)
? ? ? ? ? ? ? ? // 堆外緩存大小
? ? ? ? ? ? ? ? .offheap(ehcacheConfiguration.getOffheap(), MemoryUnit.MB)
? ? ? ? ? ? ? ? // 文件緩存大小
? ? ? ? ? ? ? ? .disk(ehcacheConfiguration.getDisk(), MemoryUnit.MB);
? ? ? ? //生成配置
? ? ? ? ExpiryPolicy expiryPolicy = ExpiryPolicyBuilder.noExpiration();
? ? ? ? CacheConfiguration config = CacheConfigurationBuilder.newCacheConfigurationBuilder(String.class, BaseSystemObject.class, resourcePoolsBuilder)
? ? ? ? ? ? ? ? //設置永不過期
? ? ? ? ? ? ? ? .withExpiry(expiryPolicy)
? ? ? ? ? ? ? ? .build();

? ? ? ? CacheManagerBuilder cacheManagerBuilder = CacheManagerBuilder.newCacheManagerBuilder()
? ? ? ? ? ? ? ? ?? ??? ? .with(CacheManagerBuilder.persistence(ehcacheConfiguration.getDiskDir()));
? ? ? ? return cacheManagerBuilder.build(true);
? ? }
}

緩存操作

緩存預熱

針對緩存框架選擇的雙寫策略,即數(shù)據(jù)庫和緩存同時寫入,所以在系統(tǒng)啟動時需要預先將數(shù)據(jù)庫數(shù)據(jù)加載到緩存中
針對單表聲明自定義注解,個性化緩存定義自定義接口

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface HPCache {

}
public interface IHPCacheInitService {

? ? String getCacheName();

? ? void initCache();
}

系統(tǒng)初始化時同步進行緩存初始化,掃描注解實體類與接口實現(xiàn)Bean

@Async
? ? public void initCache(Class runtimeClass, List<String> extraPackageNameList) {
? ? ? ? List<Class<?>> cacheEntityList = new ArrayList<>();
? ? ? ? if (!runtimeClass.getPackage().getName().equals(Application.class.getPackage().getName())) {
? ? ? ? ? ? cacheEntityList.addAll(ScanUtil.getAllClassByPackageName_Annotation(runtimeClass.getPackage(), HPCache.class));
? ? ? ? }
? ? ? ? for (String packageName : extraPackageNameList) {
? ? ? ? ? ? cacheEntityList.addAll(ScanUtil.getAllClassByPackageName_Annotation(packageName, HPCache.class));
? ? ? ? }

? ? ? ? for (Class clazz : cacheEntityList) {
? ? ? ? ? ? TableName tableName = (TableName) clazz.getAnnotation(TableName.class);
? ? ? ? ? ? List<LinkedHashMap<String, Object>> resultList = commonDTO.selectList(tableName.value(), "*", "1=1", "", new HashMap<>(), false);
? ? ? ? ? ? for (LinkedHashMap<String, Object> map : resultList) {
? ? ? ? ? ? ? ? Cache cache = cacheManager.getCache(clazz.getName(), String.class, BaseSystemObject.class);
? ? ? ? ? ? ? ? String unitguid = ConvertOp.convert2String(map.get("UnitGuid"));
? ? ? ? ? ? ? ? try {
? ? ? ? ? ? ? ? ? ? Object obj = clazz.newInstance();
? ? ? ? ? ? ? ? ? ? obj = ConvertOp.convertLinkHashMapToBean(map, obj);
? ? ? ? ? ? ? ? ? ? cache.put(unitguid, obj);
? ? ? ? ? ? ? ? } catch (Exception e) {
? ? ? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }

? ? ? ? //自定義緩存
? ? ? ? Map<String, IHPCacheInitService> res = context.getBeansOfType(IHPCacheInitService.class);
? ? ? ? for (Map.Entry en : res.entrySet()) {
? ? ? ? ? ? IHPCacheInitService service = (IHPCacheInitService) en.getValue();
? ? ? ? ? ? service.initCache();
? ? ? ? }

? ? ? ? System.out.println("緩存初始化完畢");
? ? }

需要注意,在EhcacheConfig配置類中需要進行緩存名稱的提前注冊,否則會導致操作緩存時空指針異常

? ? Map<String, Object> annotatedBeans = context.getBeansWithAnnotation(SpringBootApplication.class);
? ? ? ? Class runtimeClass = annotatedBeans.values().toArray()[0].getClass();
? ? ? ? //do,dao掃描
? ? ? ? List<String> extraPackageNameList = new ArrayList<String>();
? ? ? ? extraPackageNameList.add(Application.class.getPackage().getName());
? ? ? ? List<Class<?>> cacheEntityList = new ArrayList<>();
? ? ? ? if (!runtimeClass.getPackage().getName().equals(Application.class.getPackage().getName())) {
? ? ? ? ? ? cacheEntityList.addAll(ScanUtil.getAllClassByPackageName_Annotation(runtimeClass.getPackage(), HPCache.class));
? ? ? ? }
? ? ? ? for (String packageName : extraPackageNameList) {
? ? ? ? ? ? cacheEntityList.addAll(ScanUtil.getAllClassByPackageName_Annotation(packageName, HPCache.class));
? ? ? ? }

? ? ? ? for (Class clazz : cacheEntityList) {
? ? ? ? ? ? cacheManagerBuilder = cacheManagerBuilder.withCache(clazz.getName(), config);
? ? ? ? }

? ? ? ? //自定義緩存
? ? ? ? Map<String, IHPCacheInitService> res = context.getBeansOfType(IHPCacheInitService.class);
? ? ? ? for (Map.Entry en :res.entrySet()) {
? ? ? ? ? ? IHPCacheInitService service = (IHPCacheInitService)en.getValue();
? ? ? ? ? ? cacheManagerBuilder = cacheManagerBuilder.withCache(service.getCacheName(), config);
? ? ? ? }

更新操作

手動獲取ehcache的bean對象,調用put,repalce,delete方法進行操作

? ??? ?private ?CacheManager cacheManager = (CacheManager) SpringBootBeanUtil.getBean("ehCacheManager");
? ? public void executeUpdateOperation(String cacheName, String key, BaseSystemObject value) {
? ? ? ? Cache cache = cacheManager.getCache(cacheName, String.class, BaseSystemObject.class);
? ? ? ? if (cache.containsKey(key)) {
? ? ? ? ? ? cache.replace(key, value);
? ? ? ? } else {
? ? ? ? ? ? cache.put(key, value);
? ? ? ? }
? ? }

? ? public void executeDeleteOperation(String cacheName, String key) {
? ? ? ? Cache cache = cacheManager.getCache(cacheName, String.class, BaseSystemObject.class);
? ? ? ? cache.remove(key);
? ? }

查詢操作

緩存存儲單表以主鍵—object形式存儲,個性化緩存為key-object形式存儲,單條記錄可以通過getCache方法查詢,列表查詢需要取出整個緩存按條件進行過濾

?public Object getCache(String cacheName, String key){
? ? ? ? Cache cache = cacheManager.getCache(cacheName, String.class, BaseSystemObject.class);
? ? ? ? return cache.get(key);
? ? }

? ? public List<Object> getAllCache(String cacheName){
? ? ? ? List result = new ArrayList<>();
? ? ? ? Cache cache = cacheManager.getCache(cacheName, String.class, BaseSystemObject.class);
? ? ? ? Iterator iter = cache.iterator();
? ? ? ? while (iter.hasNext()) {
? ? ? ? ? ? Cache.Entry entry = (Cache.Entry) iter.next();
? ? ? ? ? ? result.add(entry.getValue());
? ? ? ? }
? ? ? ? return result;
? ? }

緩存與數(shù)據(jù)庫數(shù)據(jù)一致性

數(shù)據(jù)庫數(shù)據(jù)操作與緩存操作順序為先操作數(shù)據(jù)后操作緩存,在開啟數(shù)據(jù)庫事務的情況下針對單條數(shù)據(jù)單次操作是沒有問題的,如果是組合操作一旦數(shù)據(jù)庫操作發(fā)生異?;貪L,緩存并沒有回滾就會導致數(shù)據(jù)的不一致,比如執(zhí)行順序為dbop1=》cacheop1=》dbop2=》cacheop2,dbop2異常,cacheop1的操作已經(jīng)更改了緩存
這里選擇的方案是在數(shù)據(jù)庫全部執(zhí)行完畢后統(tǒng)一操作緩存,這個方案有一個缺點是如果緩存操作發(fā)生異常還是會出現(xiàn)上述問題,實際過程中緩存只是對內存的操作異常概率較小,對緩存操作持樂觀狀態(tài),同時我們提供手動重置緩存的功能,算是一個折中方案,下面概述該方案的一個實現(xiàn)

聲明自定義緩存事務注解

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface CacheTransactional {

}

聲明切面監(jiān)聽,在標記了CacheTransactional注解的方法執(zhí)行前進行Redis標識,統(tǒng)一執(zhí)行完方法體后執(zhí)行緩存操作
將緩存操作以線程id區(qū)分放入待執(zhí)行隊列中序列化到redis,提供方法統(tǒng)一操作

public class CacheExecuteModel implements Serializable {
? ? private String obejctClazzName;
? ? private String cacheName;
? ? private String key;
? ? private BaseSystemObject value;
? ? private String executeType;
}

private ?CacheManager cacheManager = (CacheManager) SpringBootBeanUtil.getBean("ehCacheManager");

? ? @Autowired
? ? private RedisUtil redisUtil;

? ? public void putCacheIntoTransition(){
? ? ? ? String threadID = Thread.currentThread().getName();
? ? ? ? System.out.println("init threadid:"+threadID);
? ? ? ? CacheExecuteModel cacheExecuteModel = new CacheExecuteModel();
? ? ? ? cacheExecuteModel.setExecuteType("option");
? ? ? ? redisUtil.redisTemplateSetForCollection(threadID,cacheExecuteModel, GlobalEnum.RedisDBNum.Cache.get_value());
? ? ? ? redisUtil.setExpire(threadID,5, TimeUnit.MINUTES, GlobalEnum.RedisDBNum.Cache.get_value());
? ? }

? ? public void putCache(String cacheName, String key, BaseSystemObject value) {
? ? ? ? if(checkCacheOptinionInTransition()){
? ? ? ? ? ? String threadID = Thread.currentThread().getName();
? ? ? ? ? ? CacheExecuteModel cacheExecuteModel = new CacheExecuteModel("update", cacheName, key, value.getClass().getName(),value);
? ? ? ? ? ? redisUtil.redisTemplateSetForCollection(threadID,cacheExecuteModel, GlobalEnum.RedisDBNum.Cache.get_value());
? ? ? ? ? ? redisUtil.setExpire(threadID,5, TimeUnit.MINUTES, GlobalEnum.RedisDBNum.Cache.get_value());
? ? ? ? }else{
? ? ? ? ? ? executeUpdateOperation(cacheName,key,value);
? ? ? ? }

? ? }

? ? public void deleteCache(String cacheName, String key) {
? ? ? ? if(checkCacheOptinionInTransition()){
? ? ? ? ? ? String threadID = Thread.currentThread().getName();
? ? ? ? ? ? CacheExecuteModel cacheExecuteModel = new CacheExecuteModel("delete", cacheName, key);
? ? ? ? ? ? redisUtil.redisTemplateSetForCollection(threadID,cacheExecuteModel, GlobalEnum.RedisDBNum.Cache.get_value());
? ? ? ? ? ? redisUtil.setExpire(threadID,5, TimeUnit.MINUTES, GlobalEnum.RedisDBNum.Cache.get_value());
? ? ? ? }else{
? ? ? ? ? ? executeDeleteOperation(cacheName,key);
? ? ? ? }
? ? }

? ? public void executeOperation(){
? ? ? ? String threadID = Thread.currentThread().getName();
? ? ? ? if(checkCacheOptinionInTransition()){
? ? ? ? ? ? List<LinkedHashMap> executeList = ?redisUtil.redisTemplateGetForCollectionAll(threadID, GlobalEnum.RedisDBNum.Cache.get_value());
? ? ? ? ? ? for (LinkedHashMap obj:executeList) {
? ? ? ? ? ? ? ? String executeType = ConvertOp.convert2String(obj.get("executeType"));
? ? ? ? ? ? ? ? if(executeType.contains("option")){
? ? ? ? ? ? ? ? ? ? continue;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? String obejctClazzName = ConvertOp.convert2String(obj.get("obejctClazzName"));
? ? ? ? ? ? ? ? String cacheName = ConvertOp.convert2String(obj.get("cacheName"));
? ? ? ? ? ? ? ? String key = ConvertOp.convert2String(obj.get("key"));
? ? ? ? ? ? ? ? LinkedHashMap valueMap = (LinkedHashMap)obj.get("value");
? ? ? ? ? ? ? ? String valueMapJson = ?JSON.toJSONString(valueMap);
? ? ? ? ? ? ? ? try{
? ? ? ? ? ? ? ? ? ? Object valueInstance = JSON.parseObject(valueMapJson,Class.forName(obejctClazzName));
? ? ? ? ? ? ? ? ? ? if(executeType.equals("update")){
? ? ? ? ? ? ? ? ? ? ? ? executeUpdateOperation(cacheName,key,(BaseSystemObject)valueInstance);
? ? ? ? ? ? ? ? ? ? }else if(executeType.equals("delete")){
? ? ? ? ? ? ? ? ? ? ? ? executeDeleteOperation(cacheName,key);
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }catch (Exception e){
? ? ? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? ? redisUtil.redisTemplateRemove(threadID,GlobalEnum.RedisDBNum.Cache.get_value());
? ? ? ? }

? ? }

? ? public boolean checkCacheOptinionInTransition(){
? ? ? ? String threadID = Thread.currentThread().getName();
? ? ? ? System.out.println("check threadid:"+threadID);
? ? ? ? return redisUtil.isValid(threadID, GlobalEnum.RedisDBNum.Cache.get_value());
? ? }

到此這篇關于SpringBoot整合Ehcache3的實現(xiàn)步驟的文章就介紹到這了,更多相關SpringBoot整合Ehcache3內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • 淺談UUID生成的原理及優(yōu)缺點

    淺談UUID生成的原理及優(yōu)缺點

    UUID是一套用于生成全局唯一標識符的標準,也被稱為GUID?(Globally?Unique?Identifier),通過使用UUID可以在分布式系統(tǒng)中生成唯一的?ID,UUID的生成方式有多種,本文將詳細講解?UUID?的生成原理、特性、實用場景以及優(yōu)缺點
    2023-06-06
  • Java線程間通信不同步問題原理與模擬實例

    Java線程間通信不同步問題原理與模擬實例

    這篇文章主要介紹了Java線程間通信不同步問題,結合實例形式分析了java線程間通信不同步問題的原理并模擬實現(xiàn)了線程間通信不同步情況下的異常輸出,需要的朋友可以參考下
    2019-10-10
  • spring中FactoryBean中的getObject()方法實例解析

    spring中FactoryBean中的getObject()方法實例解析

    這篇文章主要介紹了spring中FactoryBean中的getObject()方法實例解析,分享了相關代碼示例,小編覺得還是挺不錯的,具有一定借鑒價值,需要的朋友可以參考下
    2018-02-02
  • 舉例說明Java設計模式編程中ISP接口隔離原則的使用

    舉例說明Java設計模式編程中ISP接口隔離原則的使用

    這篇文章主要介紹了Java設計模式編程中ISP接口隔離原則的使用,接口隔離原則主張一個類對另外一個類的依賴性應當是建立在最小的接口上,需要的朋友可以參考下
    2016-02-02
  • 詳解Java對象的強、軟、弱和虛引用+ReferenceQueue

    詳解Java對象的強、軟、弱和虛引用+ReferenceQueue

    這篇文章主要介紹了詳解Java對象的強、軟、弱和虛引用+ReferenceQueue的相關資料,需要的朋友可以參考下
    2017-06-06
  • SpringBoot集成阿里巴巴Druid監(jiān)控的示例代碼

    SpringBoot集成阿里巴巴Druid監(jiān)控的示例代碼

    這篇文章主要介紹了SpringBoot集成阿里巴巴Druid監(jiān)控的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-04-04
  • 微信公眾號支付(一)如何獲取用戶openId

    微信公眾號支付(一)如何獲取用戶openId

    本篇文章給大家介紹微信公眾號支付如何獲取用戶openid,需要授權回調頁面域名等一系列途徑實現(xiàn)此功能,需要的朋友可以參考下
    2015-09-09
  • Java?SpringBoot操作Redis

    Java?SpringBoot操作Redis

    這篇文章主要介紹了SpringBoot如何操作Redis,文章中有詳細的代碼示例,有一定的參考價值,感興趣的同學可以參考閱讀
    2023-04-04
  • Java 實戰(zhàn)范例之精美網(wǎng)上音樂平臺的實現(xiàn)

    Java 實戰(zhàn)范例之精美網(wǎng)上音樂平臺的實現(xiàn)

    讀萬卷書不如行萬里路,只學書上的理論是遠遠不夠的,只有在實戰(zhàn)中才能獲得能力的提升,本篇文章手把手帶你用java+vue+Springboot+ssm+mysql+maven+redis實現(xiàn)一個前后端分離的精美網(wǎng)上音樂平臺,大家可以在過程中查缺補漏,提升水平
    2021-11-11
  • mybatis?@InsertProvider報錯問題及解決

    mybatis?@InsertProvider報錯問題及解決

    這篇文章主要介紹了mybatis?@InsertProvider報錯的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-07-07

最新評論