【Spring源碼核心篇-08】spring中配置類底層原理和源碼實現

Spring源碼核心篇整體欄目


內容鏈接地址
【一】Spring的bean的生命周期https://zhenghuisheng.blog.csdn.net/article/details/143441012
【二】深入理解spring的依賴注入和屬性填充https://zhenghuisheng.blog.csdn.net/article/details/143854482
【三】精通spring的aop的底層原理和源碼實現https://zhenghuisheng.blog.csdn.net/article/details/144012934
【四】spring中refresh刷新機制的流程和實現https://zhenghuisheng.blog.csdn.net/article/details/144118337
【五】spring中循環依賴的解決和底層實現https://zhenghuisheng.blog.csdn.net/article/details/144132213
【六】spring中事務的底層實現與執行流程https://zhenghuisheng.blog.csdn.net/article/details/144178500
【七】spring中事物傳播機制的流程和原理https://zhenghuisheng.blog.csdn.net/article/details/144178500
【八】spring中配置類底層原理和源碼實現https://zhenghuisheng.blog.csdn.net/article/details/148657333

spring配置類實現原理

  • 一. 深入理解spring配置類實現原理
    • 1,配置類方法入口checkConfigurationClassCandidate
    • 2,解析配置類doProcessConfigurationClass
      • 2.1. @PropertySource 解析
      • 2.2. @ComponentScan 解析
      • 2.3. @Import 解析
      • 2.4. @ ImportResource 解析
      • 2.5. @Bean 解析
      • 2.6. @父類解析
    • 3,注冊配置類的beanDefinition
      • 3.1. @Import注解生成BeanDefinition
      • 3.2. @Bean注解生成BeanDefinition
      • 3.3. @ImportResources注解生成BeanDefinition

如需轉載,請附上鏈接:https://blog.csdn.net/zhenghuishengq/article/details/148657333

一. 深入理解spring配置類實現原理

在spring中,內部存在一些配置類,配置注解,在我們使用這些注解的時候,可以手動的將一些配置類加載到spring容器中,類似與比較常規的 @Configuration 注解等,除了這個注解之外,spring內部也提供了多個這種注解,接下來從spring源碼中,來分析這些配置類以及配置注解

在spring源碼中,會解析配置類,校驗是否配置類的入口如下,通過下面這個方法來判斷該

ConfigurationClassUtils.checkConfigurationClassCandidate(...)

1,配置類方法入口checkConfigurationClassCandidate

其方法詳情如下,主要是通過獲取類上面的注解,然后通過注解來判斷該類是不是配置類

在這里插入圖片描述

首先會判斷這個類上面是不是加了這個 @Configuration 注解

AnnotationMetadata metadata;
// 校驗是不是加了 @Configuration 注解
if (isFullConfigurationCandidate(metadata)) {//如果加了,那么給這個注解上面加一個標記beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
}
public static boolean isFullConfigurationCandidate(AnnotationMetadata metadata) {return metadata.isAnnotated(Configuration.class.getName());
}

接下來根據源碼繼續往下走,上面是一個full重的配置類,接下來會判斷一些lite配置類,即一些比較輕的配置類

else if (isLiteConfigurationCandidate(metadata)) {beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
}

這個lite輕的配置類的具體實現如下,首先會判斷要加載的類上面的注解包不包括在 candidateIndicators 集合列表中, 這個set集合中包括的主要注解如下:Component、ComponentScan、Import、ImportResource 這四個,除了這幾個之外,下面還會判斷內部是否有 @Bean 注解

在這里插入圖片描述

private static final Set<String> candidateIndicators = new HashSet<>(8);
static {candidateIndicators.add(Component.class.getName());candidateIndicators.add(ComponentScan.class.getName());candidateIndicators.add(Import.class.getName());candidateIndicators.add(ImportResource.class.getName());
}

也就是說,只要類上面有 以下注解,那么spring就會將這些類掃描并解析成一個配置類

  • @Configuration
  • @Bean
  • @Component
  • @ComponentScan
  • @Import
  • @ImportResource

2,解析配置類doProcessConfigurationClass

在refresh方法中,會有一個 invokeBeanFactoryPostProcessors 方法,在內部就會調用到這個 doProcessConfigurationClass 真正的去解析這個配置類的方法。接下來直接看源碼,看看內部到底是如何解析的。

在這里插入圖片描述

2.1. @PropertySource 解析

首先第一步是解析帶有這個 PropertySource 注解的實體類,這個注解就是用于處理 Properties 配置文件的,將配置文件中的內容加載到spring容器內部

for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), PropertySources.class,org.springframework.context.annotation.PropertySource.class)) {if (this.environment instanceof ConfigurableEnvironment) {processPropertySource(propertySource);}
}

2.2. @ComponentScan 解析

接下來解析的是這個 ComponentScan 注解,ComponentScan說白了就是對 @Component注解的掃描,判斷類上面是否有這個 @Component注解,在前面講解bean的生命周期的時候重點的講解過。

for (AnnotationAttributes componentScan : componentScans) {//把我們掃描出來的類變為bean定義的集合 真正的解析Set<BeanDefinitionHolder> scannedBeanDefinitions =this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());//循環處理我們包掃描出來的bean定義for (BeanDefinitionHolder holder : scannedBeanDefinitions) {BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();if (bdCand == null) {bdCand = holder.getBeanDefinition();}//判斷當前掃描出來的bean定義是不是一個配置類,若是的話 直接進行遞歸解析if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {//遞歸解析 因為@Component算是lite配置類parse(bdCand.getBeanClassName(), holder.getBeanName());}}
}

首先會將這些掃描到的類解析成一個 BeanDefinition,判斷是否存在includeFilters中,excludeFilters中,然后判斷是否@Lazy @DependsOn等注解,最后將這些屬性全部注冊到beanDefinition中返回

this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName())

最后又會判斷這個類屬不屬于配置類,屬于的話再次遞歸解析,判斷這個類可不可能存在父類也需要解析成配置類等,直到返回null跳出遞歸

if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {//遞歸解析 因為@Component算是lite配置類parse(bdCand.getBeanClassName(), holder.getBeanName());
}

2.3. @Import 解析

接下來就是處理Import的注解,這個部分的解析相對繞一些。首先會調用這個 getImports 方法獲取全部帶有Import的類

processImports(configClass, sourceClass, getImports(sourceClass), true);

然后遍歷這些獲取的Import實例,里面會有三個分支,校驗這些加了Import的類上面是否是單純的加了這個注解,還是同時實現了別的接口,要對相關實現的接口做不同的判斷

for (SourceClass candidate : importCandidates) {...
}
  • 1,首先是先看只有單純加了Import的配置類,spring會直接將這種配置類進行解析注冊
else {// 當做配置類再解析,注意這里會標記:importedBy,  表示這是Import的配置的類// 再執行之前的processConfigurationClass()方法 ,this.importStack.registerImport(currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());processConfigurationClass(candidate.asConfigClass(configClass));
}		
  • 2,隨后是判斷這個加了Import注解的類,同時實現了 ImportSelector 接口,如果是的話,那么會先實例化一個 ImportSelector 組件,然后通過遞歸的方式,將一個ImportSelector組件解析成上面多個 Import 組件,最后又調用這個 processImports 方法,將解析成多個的import組件走上面的這個else邏輯
if (candidate.isAssignable(ImportSelector.class)) {// Candidate class is an ImportSelector -> delegate to it to determine importsClass<?> candidateClass = candidate.loadClass();//實例化我們的SelectImport組件ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);//調用相關的aware方法ParserStrategyUtils.invokeAwareMethods(selector, this.environment, this.resourceLoader, this.registry);//判斷是不是延時的DeferredImportSelectors,是這個類型 不進行處理if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) {this.deferredImportSelectors.add(new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector));}else {//不是延時的//調用selector的selectImportsString[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());// 所以遞歸解析-- 直到成普通組件Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);processImports(configClass, currentSourceClass, importSourceClasses, false);}
}
  • 3,最后再看這個加了Import注解,同時也實現了 ImportBeanDefinitionRegistrar 接口的方法,他和上面這個實現 ImportSelector 的方式不同,不會解析轉成多個Import,而是作為一個屬性加入到 ConfigurationClass配置類中
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {Class<?> candidateClass = candidate.loadClass();//實例話我們的ImportBeanDefinitionRegistrar對象ImportBeanDefinitionRegistrar registrar =BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);ParserStrategyUtils.invokeAwareMethods(registrar, this.environment, this.resourceLoader, this.registry);//保存我們的ImportBeanDefinitionRegistrar對象 currentSourceClass=所在配置類configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}

2.4. @ ImportResource 解析

接下來就是處理這個 ImportResource 注解,其主要實現如下

AnnotationAttributes importResource =AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
if (importResource != null) {String[] resources = importResource.getStringArray("locations");Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");for (String resource : resources) {String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);configClass.addImportedResource(resolvedResource, readerClass);}
}

其核心就在于下面這句,用于獲取本地的一些環境變量或者一些屬性,比如獲取一些 xml 文件中的一些配置屬性等,然后將內容讀取到配置文件

String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);

最后也是作為一個屬性加入到 ConfigurationClass 配置文件中,和上面實現這個 ImportBeanDefinitionRegistrar 接口的一樣,目前只是將這些屬性加入到配置文件中,還有生成具體的beanDefinition

configClass.addImportedResource(resolvedResource, readerClass);

2.5. @Bean 解析

接下來就是接下這個 @Bean注解,這里也比較簡單,就是在類中獲取全部帶有 @Bean的注解,然后去遍歷這些元數據,然后將這些打包成一個 BeanMethod實體,加入到ConfigurationClass配置文件中

// 獲取全部帶有 @Bean的方法
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}

除了在類中獲取 @Bean 注解之外,他還有一個在接口中獲取該注解的解析。比如有的接口的default方法中加了這個注解進行注入,但其實現和在類中找一致,也是將這些打包成BeanMethod實體類,加入到配置文件中

processInterfaces(configClass, sourceClass);private void processInterfaces(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {for (SourceClass ifc : sourceClass.getInterfaces()) {Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(ifc);for (MethodMetadata methodMetadata : beanMethods) {if (!methodMetadata.isAbstract()) {// A default method or other concrete method on a Java 8+ interface...configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));}}processInterfaces(configClass, ifc);}
}

2.6. @父類解析

最后就剩一個父類解析,因為很多地方涉及到遞歸解析,判斷父類是否也是一個配置類,因此需要在此處進行處理

在這里插入圖片描述

遞歸直到沒有父類需要解析,那么就會返回一個null,前面的while需要通過這個返回的null跳出遞歸,可以參考源碼實現。

// 處理配置類的父類的 ,循環再解析
if (sourceClass.getMetadata().hasSuperClass()) {String superclass = sourceClass.getMetadata().getSuperClassName();if (superclass != null && !superclass.startsWith("java") &&!this.knownSuperclasses.containsKey(superclass)) {this.knownSuperclasses.put(superclass, configClass);// Superclass found, return its annotation metadata and recursereturn sourceClass.getSuperClass();}
}
// 沒有父類解析完成
return null;

3,注冊配置類的beanDefinition

上面PropertySource 、ComponentScan 、Import 都注冊成了對應的beanDefinition,而@Bean、@ImportResource 注解目前只是封裝成了實體加載到了配置類中,還沒有進行注冊到對應beanDefinition中,那么繼續看源碼,底層是如何將后面加到配置類的幾個注冊成bean定義的

還是得回到 processConfigBeanDefinitions 中,查看這個@Bean和實現了這個 ImportBeanDefinitionRegistrar 的 @Import方法時如何解析成BeanDefinition的,這塊內容在前面講解bean的生命周期的時候詳細的講過,這個也是前面的一個流程

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {// 此處才把@Bean的方法和@Import 注冊到BeanDefinitionMap中this.reader.loadBeanDefinitions(configClasses);
}

接下來直接查看這個 loadBeanDefinitions 方法,里面也沒做特別的事情,就是一個循環

public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();//注冊我們的配置類到容器中for (ConfigurationClass configClass : configurationModel) {loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);}
}

接下來重點查看這個 loadBeanDefinitionsForConfigurationClass 方法,在這個方法中,對@Import、@Bean、@ImportResources、@ImportBeanDefinition 注解進行解析,然后生成對應的beanDefinition

在這里插入圖片描述

3.1. @Import注解生成BeanDefinition

首先會判斷這個配置類是不是導入進來的

if (configClass.isImported()) {registerBeanDefinitionForImportedConfigurationClass(configClass);
}

如果這個類是通過Import導入進來的,那么會調用這個 registerBeanDefinitionForImportedConfigurationClass 方法來將這個類注冊成 BeanDefinition,會設置一些元數據信息,bean定義,作用域等,最后通過注冊的方式將這個實體類注冊成一個BeanDefinition

在這里插入圖片描述

3.2. @Bean注解生成BeanDefinition

隨后會判斷這個配置類上面是不是通過@Bean的方式注入進來的,如果是通過@Bean方式注入進來的,前面已經將@Bean的配置類包裝成了 BeanMethod 實體類,因此只需要遍歷這個配置類中的 BeanMethods實體類集合即可

//是不是通過我們的@bean導入進來的組件
for (BeanMethod beanMethod : configClass.getBeanMethods()) {loadBeanDefinitionsForBeanMethod(beanMethod);
}

這個解析會相對復雜點,里面設計多重校驗,最后注冊成BeanDefinition

private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {//設計大量的校驗`...// 最后注冊成BeanDefinition中this.registry.registerBeanDefinition(beanName, beanDefToRegister);
}

3.3. @ImportResources注解生成BeanDefinition

隨后判斷是不是importResources注解注入進來的

private void loadBeanDefinitionsFromImportedResources(){...
}

主要是加載一些grovvy配置文件或者xml文件,然后將這些配置文件設置到環境變量中

在這里插入圖片描述
最后將這個配置文件通過reader讀取的方式加載到配置文件中

reader.loadBeanDefinitions(resource);

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/84891.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/84891.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/84891.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【無標題】在 4K 高分辨率(如 3840×2160)筆記本上運行 VMware 虛擬機時平面太小字體太小(ubuntu)

? 方法一&#xff1a;寫入 ~/.xprofile&#xff08;推薦&#xff09; 這個文件會在你登錄圖形界面前自動執行&#xff0c;適合設置縮放比例等桌面配置。 1. 打開 .xprofile 文件&#xff08;如果沒有會自動創建&#xff09;&#xff1a; nano ~/.xprofile2. 寫入以下內容&a…

「Linux文件及目錄管理」目錄結構及顯示類命令

Linux文件系統的目錄結構 Linux文件系統采用嚴格的樹形結構,所有文件和目錄都從根目錄(/)開始延伸。以下是主要目錄的詳細說明: /bin:存放系統啟動和運行所必需的二進制可執行文件,如ls、cp、mv等基本命令。/etc:存放系統配置文件,如/etc/passwd(用戶賬戶信息)、/et…

人工智能學習13-Numpy-規律數組生成

人工智能學習概述—快手視頻 人工智能學習13-Numpy-規律數組生成—快手視頻 NumPy&#xff08;Numerical Python&#xff09;是 Python 的一種開源的數值計算擴展。 這種工具可用來存儲和處理大型矩陣&#xff0c;比 Python 自身的嵌套列表 &#xff08;nested list structure…

Spring Boot 集成 Redis 實戰教程

前言 在高并發、大數據量的應用場景中&#xff0c;緩存是提升系統性能的關鍵技術。Redis 憑借其卓越的讀寫性能、豐富的數據結構和高可用性&#xff0c;成為開發者常用的緩存工具。本教程將嚴格依據Spring 官方文檔與Redis 官方文檔&#xff0c;詳細介紹 Spring Boot 與 Redis…

龍蜥開發者說:我的龍蜥開源之旅 | 第 32 期

「龍蜥開發者說」第 32 期來了&#xff01;開發者與開源社區相輔相成&#xff0c;相互成就&#xff0c;這些個人在龍蜥社區的使用心得、實踐總結和技術成長經歷都是寶貴的&#xff0c;我們希望在這里讓更多人看見技術的力量。本期故事&#xff0c;我們邀請了龍蜥社區開發者潘玨…

在mac上安裝sh腳本文件

要將 jd-gui.sh 腳本轉換為在 macOS ARM 系統上帶有自定義圖標的可點擊運行的程序&#xff0c;你可以通過創建一個應用程序包&#xff08;.app&#xff09;來實現。以下是詳細步驟&#xff1a; 步驟 1&#xff1a;創建應用程序包目錄結構 應用程序包實際上是一個特殊的目錄&a…

用bilibili一個講座視頻,生成一本科普書籍

用bilibili一個講座視頻,生成一本科普書籍 一、功能介紹1.1 智能文本處理1.2 知識提煉與結構化1.3 專業知識普及1.4 自動化書籍生成1,5 大規模處理能力二、技術特點三、應用意義3.1 教育領域3.2 研究領域3.3 內容創作3.4 企業應用四、創新價值五、使用場景示例六、操作步驟6.1 …

黑馬教程強化day3-1

目錄 一、File1.定義&#xff1a;2.創建File類的對象3.File提供的判斷文件類型、獲取文件信息功能4.File提供的創建的方法5.File類刪除文件的功能6.File提供的遍歷文件夾的方法代碼演示 二、遞歸&#xff08;了解遞歸算法&#xff0c;以便實現多級遍歷找文件&#xff09;1.定義…

milvus 總結

1. milvus 的默認 admin 角色賬號 root 的密碼 為 Milvus 2. 最開始使用命令&#xff1a; docker-compose -f milvus-standalone-docker-compose.yml up -d 啟動 milvus 后&#xff0c;使用 attu 登錄 Milvus 是不需要輸入賬號/密碼的&#xff0c;可以使用如下方式開啟 mi…

基于docker技術的單主機環境模擬測試批量客戶端

EX. 任務背景 近期接到一個需求是在一個高性能服務器上&#xff0c;模擬啟動多個待測試客戶端的場景&#xff0c;但這個客戶端程序有點特殊&#xff0c;設置了守護模式&#xff0c;并且需要管理員權限會監控系統的/dev/mem節點&#xff0c;單個環境中只能啟動一個。 當前的測…

windows上用vnc viewer 能連接mac,不能連ubuntu

如果 VNC Viewer 可以連接 macOS&#xff0c;但無法連接 Ubuntu&#xff0c;通常是由于 Ubuntu 上的 VNC 服務配置問題或網絡限制導致的。以下是逐步排查和解決方案&#xff1a; 1. 確認 Ubuntu 上已安裝并運行 VNC 服務 (1) 檢查是否安裝了 VNC 服務器 Ubuntu 常用的 VNC 服…

Electron-vite【實戰】MD 編輯器 -- 編輯區(含工具條、自定義右鍵快捷菜單、快捷鍵編輯、拖拽打開文件等)

最終效果 頁面 src/renderer/src/App.vue <div class"editorPanel"><div class"btnBox"><divv-for"(config, key) in actionDic":key"key"class"btnItem":title"config.label"click"config.a…

沒有寶塔面板的服務器上的WordPress網站打包下載到本地?

在服務器上部署的wordpress博客站&#xff0c;沒有寶塔面板&#xff0c;怎么將服務器上的wordpress打包下載到本地&#xff1f; 作者: 曉北斗NorSnow 曉北斗動態視覺設計師&#xff0c;嵐度視覺工作室執行人&#xff1b;主要從事展廳視頻制作、圖形工作站銷售、AIGC研究&#…

Atcoder Beginner Contest 410 題解報告

零、前言 經過七七四十九天的分別&#xff0c;本期 ABC 題解又和大家見面啦&#xff01; 經過七周的奮勇殺題&#xff0c;我終于達成了三個小心愿&#xff1a; 不吃罰時AK上金排名 100 100 100 以內 且 Rated&#xff08;悲催的是&#xff0c;我 ABC400 排名兩位數但沒Rate…

pyspark非安裝使用graphframes

pyspark版本3.1.3 需要文件 graphframes-0.8.2-spark3.1-s_2.12.jarspark-graphx_2.12-3.1.3.jar從 https://github.com/microsoft/adb2spark/raw/main/graphframes-0.8.2-py3-none-any.whl 下載graphframes-0.8.2-py3-none-any.whl。下載后把whl后綴改成zip&#xff0c;解壓…

[Linux入門] Linux磁盤管理與文件系統

目錄 Linux磁盤與文件系統管理詳解&#xff1a;從基礎到實踐 ??一、磁盤基礎簡述?? 1????硬盤類型??&#xff1a; ?2??機械硬盤結構??&#xff1a; 3????磁盤容量計算??&#xff1a; 公式&#xff1a;磁盤容量磁頭數柱面數每磁道扇區數每扇區字節數 …

【Flutter】性能優化總結

【Flutter】性能優化總結 Flutter 性能優化是提升應用流暢度、響應速度和用戶體驗的關鍵。可以從以下幾個方面進行優化&#xff1a; 一、UI 構建與布局優化 1、避免不必要的重建 使用 const 構造函數&#xff1a;如 const Text(Hello)&#xff0c;可以減少 Widget 重建。使用…

5、ZYNQ PL 點燈--流水燈

目錄 1、 概述 2 、硬件電路 3、 新建 VIVADO 工程 4、 添加工程文件 6、編寫流水燈功能的Verilog代碼 7 、添加管腳約束文件 8、 RTL 仿真 8.1 添加仿真測試源碼 8.2 仿真結果 9、 編譯并且產生 bit 文件 10、 下載程序 11、實驗結果 ?編輯12、總結 1、 概述 本…

HTML5 浮動

1. 常見網頁布局 1-3-1布局 1-2-1布局 2. 標準文檔流 3. display屬性? display&#xff1a; block 給span元素設置成block display&#xff1a; inline 給div元素設置成inline display&#xff1a; inline-block 給div和span元素設置為inline-block display&#xff1a; no…

若依使用RedisCache需要注意的事項

存入redis對象的時候會帶一個type字段&#xff0c;此處需要注意 存入方&#xff1a; 此處需要注意&#xff0c;存入redis的時候會帶一個type&#xff0c;也就是類的路徑名 redisCache.setCacheObject(screenPlayQueueName, userDemondDto,userDemondDto.getPlayDuration().in…