版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
第SpringBoot整合Ehcache3的實現(xiàn)步驟公司部門老項目要遷移升級java版本,需要進(jìn)行緩存相關(guān)操作,原框架未支持這部分,經(jīng)過調(diào)研java相關(guān)緩存方案大致分為ehcache和redis兩種,redis的value最大值為500mb且超過1mb會對存取有性能影響,業(yè)務(wù)系統(tǒng)需要支持列表查詢緩存就不可避免的涉及到大量的數(shù)據(jù)存取過濾,ehcache支持內(nèi)存+磁盤緩存不用擔(dān)心緩存容量問題,所以框架初步版本決定集成ehcache3,設(shè)計流程結(jié)構(gòu)如下圖所示
maven引用
dependency
groupIdorg.springframework.boot/groupId
artifactIdspring-boot-starter-cache/artifactId
/dependency
dependency
groupIdorg.ehcache/groupId
artifactIdehcache/artifactId
/dependency
個性化配置
#緩存配置
cache:
ehcache:
heap:1000
offheap:100
disk:500
diskDir:tempfiles/cache/
@Component
@ConfigurationProperties(frmae.cache.ehcache)
publicclassEhcacheConfiguration{
/**
*ehcacheheap大小
*jvm內(nèi)存中緩存的key數(shù)量
*/
privateintheap;
/**
*ehcacheoffheap大小
*堆外內(nèi)存大小,單位:MB
*/
privateintoffheap;
/**
*磁盤持久化目錄
*/
privateStringdiskDir;
/**
*ehcachedisk
*持久化到磁盤的大小,單位:MB
*diskDir有效時才生效
*/
privateintdisk;
publicEhcacheConfiguration(){
heap=1000;
offheap=100;
disk=500;
diskDir=tempfiles/cache/
}
}
代碼注入配置
因為springboot默認(rèn)緩存優(yōu)先注入redis配置,所以需要手動聲明bean進(jìn)行注入,同時ehcache的value值必須支持序列化接口,不能使用Object代替,這里聲明一個緩存基類,所有緩存value對象必須繼承該類
publicclassBaseSystemObjectimplementsSerializable{
}
@Configuration
@EnableCaching
publicclassEhcacheConfig{
@Autowired
privateEhcacheConfigurationehcacheConfiguration;
@Autowired
privateApplicationContextcontext;
@Bean(name=ehCacheManager)
publicCacheManagergetCacheManager(){
//資源池生成器配置持久化
ResourcePoolsBuilderresourcePoolsBuilder=ResourcePoolsBuilder.newResourcePoolsBuilder()
//堆內(nèi)緩存大小
.heap(ehcacheConfiguration.getHeap(),EntryUnit.ENTRIES)
//堆外緩存大小
.offheap(ehcacheConfiguration.getOffheap(),MemoryUnit.MB)
//文件緩存大小
.disk(ehcacheConfiguration.getDisk(),MemoryUnit.MB);
//生成配置
ExpiryPolicyexpiryPolicy=ExpiryPolicyBuilder.noExpiration();
CacheConfigurationconfig=CacheConfigurationBuilder.newCacheConfigurationBuilder(String.class,BaseSystemObject.class,resourcePoolsBuilder)
//設(shè)置永不過期
.withExpiry(expiryPolicy)
.build();
CacheManagerBuildercacheManagerBuilder=CacheManagerBuilder.newCacheManagerBuilder()
.with(CacheManagerBuilder.persistence(ehcacheConfiguration.getDiskDir()));
returncacheManagerBuilder.build(true);
}
}
針對緩存框架選擇的雙寫策略,即數(shù)據(jù)庫和緩存同時寫入,所以在系統(tǒng)啟動時需要預(yù)先將數(shù)據(jù)庫數(shù)據(jù)加載到緩存中
針對單表聲明自定義注解,個性化緩存定義自定義接口
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public@interfaceHPCache{
}
publicinterfaceIHPCacheInitService{
StringgetCacheName();
voidinitCache();
}
系統(tǒng)初始化時同步進(jìn)行緩存初始化,掃描注解實體類與接口實現(xiàn)Bean
@Async
publicvoidinitCache(ClassruntimeClass,ListStringextraPackageNameList){
ListClasscacheEntityList=newArrayList();
if(!runtimeClass.getPackage().getName().equals(Application.class.getPackage().getName())){
cacheEntityList.addAll(ScanUtil.getAllClassByPackageName_Annotation(runtimeClass.getPackage(),HPCache.class));
}
for(StringpackageName:extraPackageNameList){
cacheEntityList.addAll(ScanUtil.getAllClassByPackageName_Annotation(packageName,HPCache.class));
}
for(Classclazz:cacheEntityList){
TableNametableName=(TableName)clazz.getAnnotation(TableName.class);
ListLinkedHashMapString,ObjectresultList=commonDTO.selectList(tableName.value(),*,1=1,,newHashMap(),false);
for(LinkedHashMapString,Objectmap:resultList){
Cachecache=cacheManager.getCache(clazz.getName(),String.class,BaseSystemObject.class);
Stringunitguid=ConvertOp.convert2String(map.get(UnitGuid));
try{
Objectobj=clazz.newInstance();
obj=ConvertOp.convertLinkHashMapToBean(map,obj);
cache.put(unitguid,obj);
}catch(Exceptione){
e.printStackTrace();
}
}
}
//自定義緩存
MapString,IHPCacheInitServiceres=context.getBeansOfType(IHPCacheInitService.class);
for(Map.Entryen:res.entrySet()){
IHPCacheInitServiceservice=(IHPCacheInitService)en.getValue();
service.initCache();
}
System.out.println(緩存初始化完畢
}
需要注意,在EhcacheConfig配置類中需要進(jìn)行緩存名稱的提前注冊,否則會導(dǎo)致操作緩存時空指針異常
MapString,ObjectannotatedBeans=context.getBeansWithAnnotation(SpringBootApplication.class);
ClassruntimeClass=annotatedBeans.values().toArray()[0].getClass();
//do,dao掃描
ListStringextraPackageNameList=newArrayListString
extraPackageNameList.add(Application.class.getPackage().getName());
ListClasscacheEntityList=newArrayList();
if(!runtimeClass.getPackage().getName().equals(Application.class.getPackage().getName())){
cacheEntityList.addAll(ScanUtil.getAllClassByPackageName_Annotation(runtimeClass.getPackage(),HPCache.class));
}
for(StringpackageName:extraPackageNameList){
cacheEntityList.addAll(ScanUtil.getAllClassByPackageName_Annotation(packageName,HPCache.class));
}
for(Classclazz:cacheEntityList){
cacheManagerBuilder=cacheManagerBuilder.withCache(clazz.getName(),config);
}
//自定義緩存
MapString,IHPCacheInitServiceres=context.getBeansOfType(IHPCacheInitService.class);
for(Map.Entryen:res.entrySet()){
IHPCacheInitServiceservice=(IHPCacheInitService)en.getValue();
cacheManagerBuilder=cacheManagerBuilder.withCache(service.getCacheName(),config);
}
手動獲取ehcache的bean對象,調(diào)用put,repalce,delete方法進(jìn)行操作
privateCacheManagercacheManager=(CacheManager)SpringBootBeanUtil.getBean(ehCacheManager
publicvoidexecuteUpdateOperation(StringcacheName,Stringkey,BaseSystemObjectvalue){
Cachecache=cacheManager.getCache(cacheName,String.class,BaseSystemObject.class);
if(cache.containsKey(key)){
cache.replace(key,value);
}else{
cache.put(key,value);
}
}
publicvoidexecuteDeleteOperation(StringcacheName,Stringkey){
Cachecache=cacheManager.getCache(cacheName,String.class,BaseSystemObject.class);
cache.remove(key);
}
緩存存儲單表以主鍵object形式存儲,個性化緩存為key-object形式存儲,單條記錄可以通過getCache方法查詢,列表查詢需要取出整個緩存按條件進(jìn)行過濾
publicObjectgetCache(StringcacheName,Stringkey){
Cachecache=cacheManager.getCache(cacheName,String.class,BaseSystemObject.class);
returncache.get(key);
}
publicListObjectgetAllCache(StringcacheName){
Listresult=newArrayList();
Cachecache=cacheManager.getCache(cacheName,String.class,BaseSystemObject.class);
Iteratoriter=cache.iterator();
while(iter.hasNext()){
Cache.Entryentry=(Cache.Entry)iter.next();
result.add(entry.getValue());
}
returnresult;
}
緩存與數(shù)據(jù)庫數(shù)據(jù)一致性
數(shù)據(jù)庫數(shù)據(jù)操作與緩存操作順序為先操作數(shù)據(jù)后操作緩存,在開啟數(shù)據(jù)庫事務(wù)的情況下針對單條數(shù)據(jù)單次操作是沒有問題的,如果是組合操作一旦數(shù)據(jù)庫操作發(fā)生異?;貪L,緩存并沒有回滾就會導(dǎo)致數(shù)據(jù)的不一致,比如執(zhí)行順序為dbop1=》cacheop1=》dbop2=》cacheop2,dbop2異常,cacheop1的操作已經(jīng)更改了緩存
這里選擇的方案是在數(shù)據(jù)庫全部執(zhí)行完畢后統(tǒng)一操作緩存,這個方案有一個缺點是如果緩存操作發(fā)生異常還是會出現(xiàn)上述問題,實際過程中緩存只是對內(nèi)存的操作異常概率較小,對緩存操作持樂觀狀態(tài),同時我們提供手動重置緩存的功能,算是一個折中方案,下面概述該方案的一個實現(xiàn)
聲明自定義緩存事務(wù)注解
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public@interfaceCacheTransactional{
}
聲明切面監(jiān)聽,在標(biāo)記了CacheTransactional注解的方法執(zhí)行前進(jìn)行Redis標(biāo)識,統(tǒng)一執(zhí)行完方法體后執(zhí)行緩存操作
將緩存操作以線程id區(qū)分放入待執(zhí)行隊列中序列化到redis,提供方法統(tǒng)一操作
publicclassCacheExecuteModelimplementsSerializable{
privateStringobejctClazzName;
privateStringcacheName;
privateStringkey;
privateBaseSystemObjectvalue;
privateStringexecuteType;
privateCacheManagercacheManager=(CacheManager)SpringBootBeanUtil.getBean(ehCacheManager
@Autowired
privateRedisUtilredisUtil;
publicvoidputCacheIntoTransition(){
StringthreadID=Thread.currentThread().getName();
System.out.println(initthreadid:+threadID);
CacheExecuteModelcacheExecuteModel=newCacheExecuteModel();
cacheExecuteModel.setExecuteType(option
redisUtil.redisTemplateSetForCollection(threadID,cacheExecuteModel,GlobalEnum.RedisDBNum.Cache.get_value());
redisUtil.setExpire(threadID,5,TimeUnit.MINUTES,GlobalEnum.RedisDBNum.Cache.get_value());
}
publicvoidputCache(StringcacheName,Stringkey,BaseSystemObjectvalue){
if(checkCacheOptinionInTransition()){
StringthreadID=Thread.currentThread().getName();
CacheExecuteModelcacheExecuteModel=newCacheExecuteModel(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);
}
}
publicvoiddeleteCache(StringcacheName,Stringkey){
if(checkCacheOptinionInTransition()){
StringthreadID=Thread.currentThread().getName();
CacheExecuteModelcacheExecuteModel=newCacheExecuteModel(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);
}
}
publicvoidexecuteOperation(){
StringthreadID=Thread.currentThread().getName();
if(checkCacheOptinionInTransition()){
ListLinkedHashMapexecuteList=redisUtil.redisTemplateGetForCollectionAll(threadID,GlobalEnum.RedisDBNum.Cache.get_value());
for(LinkedHashMapobj:executeList){
StringexecuteType=ConvertOp.convert2String(obj.get(executeType));
if(executeType.contains(option)){
continue;
}
StringobejctClazzName
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2024年石家莊信息工程職業(yè)學(xué)院輔導(dǎo)員考試筆試真題匯編附答案
- 2024年西安健康工程職業(yè)學(xué)院輔導(dǎo)員考試筆試真題匯編附答案
- 2024年重慶機電職業(yè)技術(shù)大學(xué)輔導(dǎo)員考試筆試題庫附答案
- 2024年長沙工業(yè)學(xué)院輔導(dǎo)員考試筆試真題匯編附答案
- 2025下半年四川文理學(xué)院選調(diào)2人備考題庫必考題
- 2025云南昆明西山區(qū)長水教育集團(tuán)招聘4人備考題庫及答案解析(奪冠)
- 2025南平武夷新區(qū)業(yè)務(wù)部門招聘3人參考題庫及答案1套
- 2025年河北科技學(xué)院輔導(dǎo)員招聘考試真題匯編附答案
- 2025年漯河市農(nóng)業(yè)農(nóng)村局所屬事業(yè)單位人才引進(jìn)3人備考題庫及答案1套
- 2025河南周口市商水縣招錄警務(wù)助理人員體能測試參考題庫及答案1套
- 北京通州產(chǎn)業(yè)服務(wù)有限公司招聘考試備考題庫及答案解析
- 2025-2026學(xué)年滬科版八年級數(shù)學(xué)上冊期末測試卷(含答案)
- 委托市場調(diào)研合同范本
- 消防維保計劃實施方案
- 有子女離婚協(xié)議書
- 2026四川省引大濟岷水資源開發(fā)限公司公開招聘易考易錯模擬試題(共500題)試卷后附參考答案
- 2025至2030中國汽車檢測行業(yè)市場深度研究與戰(zhàn)略咨詢分析報告
- 2026年南昌健康職業(yè)技術(shù)學(xué)院單招職業(yè)技能考試備考試題附答案詳解
- 2026年安徽糧食工程職業(yè)學(xué)院高職單招職業(yè)適應(yīng)性考試備考試題及答案詳解
- 雨課堂學(xué)堂在線學(xué)堂云《中國電影經(jīng)典影片鑒賞(北京師范大學(xué))》單元測試考核答案
- 四川水利安全b證考試試題及答案
評論
0/150
提交評論