前言
閱讀準備
由于Spring源碼分析是一個前后聯(lián)系比較強的過程,而且這邊分析,也是按照代碼順序講解的,所以不了解前置知識的情況下,大概率沒辦法看懂當前的內(nèi)容。所以,特別推薦看看我前面的文章(自上而下次序):
- Spring底層核心原理解析——引導篇【學習難度:★★☆☆☆】
- 手寫簡易Spring容器過程分析——引導篇【學習難度:★★☆☆☆】
- Spring之底層架構(gòu)核心概念解析【學習難度:★★★☆☆,重要程度:★★★★★】
- Bean的生命周期流程圖【學習難度:☆☆☆☆☆,重要程度:★★★★★】
(PS:特別是《Bean的生命周期流程圖》,幫大家【開天眼】,先了解下流程。畢竟【通過業(yè)務了解代碼,遠比通過代碼了解業(yè)務簡單的多】?。。。。?/mark>
(PS:特別是《Bean的生命周期流程圖》,幫大家【開天眼】,先了解下流程。畢竟【通過業(yè)務了解代碼,遠比通過代碼了解業(yè)務簡單的多】?。。。。?/mark>
(PS:特別是《Bean的生命周期流程圖》,幫大家【開天眼】,先了解下流程。畢竟【通過業(yè)務了解代碼,遠比通過代碼了解業(yè)務簡單的多】?。。。。?/mark>
閱讀指引
Spring最重要的功能就是幫助程序員創(chuàng)建對象(也就是IOC),而啟動Spring就是為創(chuàng)建Bean對象做準備,所以我們先明白Spring到底是怎么去創(chuàng)建Bean的,也就是先弄明白Bean的生命周期。
Bean的生命周期就是指:在Spring中,一個Bean是如何生成的,如何銷毀的。
本節(jié)課的內(nèi)容,將會以下面這段代碼為入口講解:
public class MyApplicationTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext("org.tuling.spring");
Object newUser = context.getBean("newUser");
System.out.println(newUser);
}
}
主要用到的是如下Spring容器的構(gòu)造方法:
/**
* 創(chuàng)建一個新的AnnotationConfigApplicationContext,掃描給定包中的組件,為這些組件注冊bean定義,并自動刷新上下文。
* 參數(shù):
* baseppackages——要掃描組件類的包
*/
public AnnotationConfigApplicationContext(String... basePackages) {
this();
scan(basePackages);
refresh();
}
閱讀建議
- 看源碼,切記糾結(jié)細枝末節(jié),不然很容易陷進去。正常來說,看主要流程就好了
- 遇到不懂的,多看看類注釋或者方法注釋。Spring這種優(yōu)秀源碼,注釋真的非常到位
- 如果你是idea用戶,多用F11的書簽功能。
- Ctrl + F11 選中文件 / 文件夾,使用助記符設定 / 取消書簽 (必備)
- Shift + F11 彈出書簽顯示層 (必備)
- Ctrl +1,2,3…9 定位到對應數(shù)值的書簽位置 (必備)
閱讀導航
系列上一篇文章:《【Spring專題】Spring之底層架構(gòu)核心概念解析》
系列下一篇文章:《【Spring專題】Spring之Bean的生命周期源碼解析——階段二(一)(IOC之實例化)》
課程內(nèi)容
一、生成BeanDefinition
1.1 簡單回顧
如果大家看過我前面的文章,應該會知道,BeanDefiniton
的生成,是在生產(chǎn)Bean之前的【掃描】階段。如下圖所示:
不過咱也說過,這只是簡單實現(xiàn)而已,事實上,Spring實現(xiàn)這個掃描過程,涉及到了3個核心類,10個核心方法!
*1.2 概念回顧
在這個【掃描】過程中,涉及到了一些Spring底層設計的概念,我在上一個筆記里面有大概介紹過,不記得的同學記得回去翻一翻。
主要涉及的概念有:
- BeanDefinition(設計圖紙):BeanDefinition表示Bean定義,BeanDefinition中存在很多屬性用來描述一個Bean的特征
- ClassPathBeanDefinitionScanner(圖紙注冊器):用于注冊圖紙
- BeanFacotory(Bean工廠):生產(chǎn)Bean。不過實際上,這里用到
DefaultListableBeanFactory
這個類的BeanDefinitionRegistry
接口的注冊能力
文章鏈接:
《【Spring專題】Spring之底層架構(gòu)核心概念解析》
1.3 核心方法講解
我們在前面提到過,整個掃描流程會涉及到【3個核心類,10個核心方法】。下面,我們將會按照調(diào)用次序,依次講解各個方法。
二、方法講解
整個掃描流程的入口,是下面代碼中的scan()
方法,而最終調(diào)用的是ClassPathBeanDefinitionScanner.scan()
/**
* 創(chuàng)建一個新的AnnotationConfigApplicationContext,掃描給定包中的組件,為這些組件注冊bean定義,并自動刷新上下文。
* 參數(shù):
* baseppackages——要掃描組件類的包
*/
public AnnotationConfigApplicationContext(String... basePackages) {
this();
scan(basePackages);
refresh();
}
public void scan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
StartupStep scanPackages = this.getApplicationStartup().start("spring.context.base-packages.scan")
.tag("packages", () -> Arrays.toString(basePackages));
this.scanner.scan(basePackages);
scanPackages.end();
}
2.1 ClassPathBeanDefinitionScanner#scan
全路徑:org.springframework.context.annotation.ClassPathBeanDefinitionScanner#scan
方法注釋:在指定的基本包中執(zhí)行掃描
源碼如下:
public int scan(String... basePackages) {
int beanCountAtScanStart = this.registry.getBeanDefinitionCount();
doScan(basePackages);
// Register annotation config processors, if necessary.
if (this.includeAnnotationConfig) {
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
}
但其實真正干活的還不是這里,而是里面的doScan()
2.2 ClassPathBeanDefinitionScanner#doScan
方法調(diào)用鏈:由 2.1中的scan()調(diào)用進來
全路徑:org.springframework.context.annotation.ClassPathBeanDefinitionScanner#doScan
方法注釋:在指定的基包中執(zhí)行掃描,返回已注冊的bean定義。此方法不注冊注釋配置處理程序,而是將此工作留給調(diào)用者。
源碼如下:
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
for (String basePackage : basePackages) {
// 尋找候選的BeanDefinition
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
for (BeanDefinition candidate : candidates) {
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
// 判斷是否要設置BeanDefinition屬性
if (candidate instanceof AbstractBeanDefinition) {
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
// 判斷是否要設置通用的注解BeanDefiniton屬性
if (candidate instanceof AnnotatedBeanDefinition) {
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
// 判斷是否注冊BeanDefinition
if (checkCandidate(beanName, candidate)) {
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
方法解讀:這個代碼看似很多,其實整體來說比較簡單,分為4個步驟
- 先掃描classpath下所有的class,尋找候選的BeanDefinition。至于什么是候選的,后面會講解
- 遍歷找到的候選BeanDefinition,判斷是否需要設置BeanDefinition的一些屬性。比如默認屬性等
- 判斷是否要設置通用的注解BeanDefiniton屬性
- 判斷是否要注冊BeanDefinition,畢竟可能出現(xiàn)重復的BeanDefinition
2.3 ClassPathScanningCandidateComponentProvider#findCandidateComponents
方法調(diào)用鏈:由 2.2中的doScan()調(diào)用進來
全路徑:org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider#findCandidateComponents
方法注釋:掃描類路徑上的候選Component。
源碼如下:
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
}
else {
return scanCandidateComponents(basePackage);
}
}
方法解讀:這里有一個if-else
,但通常都是進入else
。if
里面的情況我們在業(yè)務開發(fā)中基本不會用到,這是一個為了加快掃描包的策略,通過使用索引思想。怎么實現(xiàn)呢?就是在resource
下新建一個spring.components
配置文件(K-V格式)。如下:
org.tuling.spring.bean.User = org.springframework.stereotype.Component
通過直接告訴Spring哪些是候選的Component,免除了掃描所有class文件篩選的過程,從而提升了效率。
2.4 ClassPathScanningCandidateComponentProvider#scanCandidateComponents
方法調(diào)用鏈:由 2.3中的findCandidateComponents()調(diào)用進來
全路徑:org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider#scanCandidateComponents
方法注釋:掃描類路徑上的候選Component。
源碼如下:
private Set<org.springframework.beans.factory.config.BeanDefinition> scanCandidateComponents(String basePackage) {
Set<BeanDefinition> candidates = new LinkedHashSet<>();
try {
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + '/' + this.resourcePattern;
Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
boolean traceEnabled = logger.isTraceEnabled();
boolean debugEnabled = logger.isDebugEnabled();
for (Resource resource : resources) {
if (traceEnabled) {
logger.trace("Scanning " + resource);
}
try {
// 讀取類元信息
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
// 第一層判斷是否為候選組件,判斷核心為:是否需要過濾
if (isCandidateComponent(metadataReader)) {
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
sbd.setSource(resource);
// 第二層判斷是否為候選組件,判斷核心為:是否獨立、抽象類等
if (isCandidateComponent(sbd)) {
if (debugEnabled) {
logger.debug("Identified candidate component class: " + resource);
}
candidates.add(sbd);
}
else {
if (debugEnabled) {
logger.debug("Ignored because not a concrete top-level class: " + resource);
}
}
}
else {
if (traceEnabled) {
logger.trace("Ignored because not matching any filter: " + resource);
}
}
}
catch (FileNotFoundException ex) {
if (traceEnabled) {
logger.trace("Ignored non-readable " + resource + ": " + ex.getMessage());
}
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to read candidate component class: " + resource, ex);
}
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
}
return candidates;
}
方法解讀:代碼看著很長,實際上很簡單。主要分為4個步驟
- 讀取類元信息(從磁盤中讀取)
- 首先,通過ResourcePatternResolver獲得指定包路徑下的所有.class文件(Spring源碼中將此文件包裝成了Resource對象)
- 遍歷每個Resource對象
- 利用MetadataReaderFactory解析Resource對象得到MetadataReader(在Spring源碼中MetadataReaderFactory具體的實現(xiàn)類為CachingMetadataReaderFactory,MetadataReader的具體實現(xiàn)類為SimpleMetadataReader)
- 判斷是否為候選組件,判斷核心為:是否需要過濾(第一個
isCandidateComponent
)- 利用MetadataReader進行excludeFilters和includeFilters,以及條件注解@Conditional的篩選(條件注解并不能理解:某個類上是否存在@Conditional注解,如果存在則調(diào)用注解中所指定的類的match方法進行匹配,匹配成功則通過篩選,匹配失敗則pass掉。)
- 篩選通過后,基于metadataReader生成ScannedGenericBeanDefinition
- 判斷是否為候選組件,判斷核心為:是否獨立、抽象類等。(第二個
isCandidateComponent
)(注意:他跟上面的isCandidateComponent
不是同一個東西,屬于方法重載) - 如果篩選通過,那么就表示掃描到了一個Bean,將ScannedGenericBeanDefinition加入結(jié)果集
MetadataReader表示類的元數(shù)據(jù)讀取器,主要包含了一個AnnotationMetadata,功能有
- 獲取類的名字、
- 獲取父類的名字
- 獲取所實現(xiàn)的所有接口名
- 獲取所有內(nèi)部類的名字
- 判斷是不是抽象類
- 判斷是不是接口
- 判斷是不是一個注解
- 獲取擁有某個注解的方法集合
- 獲取類上添加的所有注解信息
- 獲取類上添加的所有注解類型集合
2.5 ClassPathScanningCandidateComponentProvider#isCandidateComponent
方法調(diào)用鏈:由 2.4中的scanCandidateComponents()調(diào)用進來
全路徑:org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider#isCandidateComponent
方法注釋:確定給定的類是否不匹配任何排除篩選器,而匹配至少一個包含篩選器。
源碼如下:
protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
for (TypeFilter tf : this.excludeFilters) {
if (tf.match(metadataReader, getMetadataReaderFactory())) {
return false;
}
}
for (TypeFilter tf : this.includeFilters) {
if (tf.match(metadataReader, getMetadataReaderFactory())) {
return isConditionMatch(metadataReader);
}
}
return false;
}
方法解讀:這里只是校驗,當前類,是否在過濾器排除選項以內(nèi)。我估計很多朋友想到的都是@ComponentScan
注解里面的includeFilter
跟excludeFilter
屬性。只能說不完全正確。
因為,在我們啟動容器創(chuàng)建ClassPathBeanDefinitionScanner
也會添加默認的過濾策略。如下所示:
/**
* 注冊@Component的默認過濾器。
* 這將隱式注冊所有帶有@Component元注釋的注釋,包括@Repository、@Service和@Controller構(gòu)造型注釋。
* 還支持Java EE 6的javax.annotation.ManagedBean和JSR-330的javax.inject.Named注釋(如果可用)。
*/
protected void registerDefaultFilters() {
this.includeFilters.add(new AnnotationTypeFilter(Component.class));
ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
try {
this.includeFilters.add(new AnnotationTypeFilter(
((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
logger.trace("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
}
catch (ClassNotFoundException ex) {
// JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.
}
try {
this.includeFilters.add(new AnnotationTypeFilter(
((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
logger.trace("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
}
catch (ClassNotFoundException ex) {
// JSR-330 API not available - simply skip.
}
}
2.6 ClassPathScanningCandidateComponentProvider#isCandidateComponent
方法調(diào)用鏈:由 2.4中的scanCandidateComponents()調(diào)用進來
全路徑:org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider#isCandidateComponent
方法注釋:確定給定的bean定義是否符合候選條件。默認實現(xiàn)檢查類是否不是接口,是否依賴于封閉類。
源碼如下:
/**
*確定給定的bean定義是否符合候選條件。
* 默認實現(xiàn)檢查類是否不是接口,是否依賴于封閉類。
* 可以在子類中重寫。
*/
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
AnnotationMetadata metadata = beanDefinition.getMetadata();
return (metadata.isIndependent() && (metadata.isConcrete() ||
(metadata.isAbstract() && metadata.hasAnnotatedMethods(Lookup.class.getName()))));
}
方法解讀:這里有2個比較陌生的,那就是,什么是獨立類,以及Lookup注解。
- 獨立類,及不是普通內(nèi)部類(靜態(tài)內(nèi)部類是獨立類)
- Lookup注解,自己去百度使用方法
總結(jié)方法,判斷是候選Component的條件是:
- 首先是獨立類
- 要么是具體的子類,要么就是:有Lookup注解的抽象類
2.7 ClassPathBeanDefinitionScanner#postProcessBeanDefinition
方法調(diào)用鏈:由 2.2中的doScan()調(diào)用進來
全路徑:org.springframework.context.annotation.ClassPathBeanDefinitionScanner#postProcessBeanDefinition
方法注釋:掃描類路徑上的候選Component。
源碼如下:
/**
* 除了通過掃描組件類檢索到的內(nèi)容之外,還可以對給定的bean定義應用進一步的設置。
*/
protected void postProcessBeanDefinition(AbstractBeanDefinition beanDefinition, String beanName) {
beanDefinition.applyDefaults(this.beanDefinitionDefaults);
if (this.autowireCandidatePatterns != null) {
beanDefinition.setAutowireCandidate(PatternMatchUtils.simpleMatch(this.autowireCandidatePatterns, beanName));
}
}
方法解讀:這里主要還初始化了BeanDefinition一些默認屬性beanDefinition.applyDefaults(this.beanDefinitionDefaults);
源碼如下:
public void applyDefaults(BeanDefinitionDefaults defaults) {
Boolean lazyInit = defaults.getLazyInit();
if (lazyInit != null) {
setLazyInit(lazyInit);
}
setAutowireMode(defaults.getAutowireMode());
setDependencyCheck(defaults.getDependencyCheck());
setInitMethodName(defaults.getInitMethodName());
setEnforceInitMethod(false);
setDestroyMethodName(defaults.getDestroyMethodName());
setEnforceDestroyMethod(false);
}
2.8 AnnotationConfigUtils.processCommonDefinitionAnnotations
方法調(diào)用鏈:由 2.2中的doScan()調(diào)用進來
全路徑:org.springframework.context.annotation.AnnotationConfigUtils#processCommonDefinitionAnnotations
方法注釋:根據(jù)注解累類元信息,設置BeanDefinition注解相關(guān)屬性。
源碼如下:
public static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd) {
processCommonDefinitionAnnotations(abd, abd.getMetadata());
}
static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) {
AnnotationAttributes lazy = attributesFor(metadata, Lazy.class);
if (lazy != null) {
abd.setLazyInit(lazy.getBoolean("value"));
}
else if (abd.getMetadata() != metadata) {
lazy = attributesFor(abd.getMetadata(), Lazy.class);
if (lazy != null) {
abd.setLazyInit(lazy.getBoolean("value"));
}
}
if (metadata.isAnnotated(Primary.class.getName())) {
abd.setPrimary(true);
}
AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class);
if (dependsOn != null) {
abd.setDependsOn(dependsOn.getStringArray("value"));
}
AnnotationAttributes role = attributesFor(metadata, Role.class);
if (role != null) {
abd.setRole(role.getNumber("value").intValue());
}
AnnotationAttributes description = attributesFor(metadata, Description.class);
if (description != null) {
abd.setDescription(description.getString("value"));
}
}
沒啥好解讀的,很簡單的判斷
2.9 ClassPathBeanDefinitionScanner#checkCandidate
方法調(diào)用鏈:由 2.2中的doScan()調(diào)用進來
全路徑:org.springframework.context.annotation.ClassPathBeanDefinitionScanner#checkCandidate
方法注釋:檢查給定的候選bean名稱,確定是否需要注冊相應的bean定義,或者是否與現(xiàn)有定義沖突。
源碼如下:
protected boolean checkCandidate(String beanName, BeanDefinition beanDefinition) throws IllegalStateException {
if (!this.registry.containsBeanDefinition(beanName)) {
return true;
}
BeanDefinition existingDef = this.registry.getBeanDefinition(beanName);
BeanDefinition originatingDef = existingDef.getOriginatingBeanDefinition();
if (originatingDef != null) {
existingDef = originatingDef;
}
if (isCompatible(beanDefinition, existingDef)) {
return false;
}
throw new ConflictingBeanDefinitionException("Annotation-specified bean name '" + beanName +
"' for bean class [" + beanDefinition.getBeanClassName() + "] conflicts with existing, " +
"non-compatible bean definition of same name and class [" + existingDef.getBeanClassName() + "]");
}
方法解讀:這里正常來說,要么返回true
,要么就是重復定義相同名字的Bean
然后拋出異常。直接返回false
,通常是存在父子容器的情況下。
2.10 DefaultListableBeanFactory#registerBeanDefinition
方法調(diào)用鏈:由 2.2中的doScan()調(diào)用進來
全路徑:org.springframework.beans.factory.support.DefaultListableBeanFactory#registerBeanDefinition
方法注釋:用這個注冊中心注冊一個新的bean定義。必須支持RootBeanDefinition和ChildBeanDefinition。
源碼如下:
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
if (existingDefinition != null) {
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
}
else if (existingDefinition.getRole() < beanDefinition.getRole()) {
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
if (logger.isInfoEnabled()) {
logger.info("Overriding user-defined bean definition for bean '" + beanName +
"' with a framework-generated bean definition: replacing [" +
existingDefinition + "] with [" + beanDefinition + "]");
}
}
else if (!beanDefinition.equals(existingDefinition)) {
if (logger.isDebugEnabled()) {
logger.debug("Overriding bean definition for bean '" + beanName +
"' with a different definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
else {
if (logger.isTraceEnabled()) {
logger.trace("Overriding bean definition for bean '" + beanName +
"' with an equivalent definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
synchronized (this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition);
List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
removeManualSingletonName(beanName);
}
}
else {
// Still in startup registration phase
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
removeManualSingletonName(beanName);
}
this.frozenBeanDefinitionNames = null;
}
if (existingDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
else if (isConfigurationFrozen()) {
clearByTypeCache();
}
}
方法解讀:這個就稍微復雜一點了,我也沒細看。而且,這個隱藏的挺深的,雖然是從doScan()
里面進調(diào)用的,但是本質(zhì)上是調(diào)用AnnotationConfigApplicationContext
繼承自GenericApplicationContext
的registerBeanDefinition
方法
三、掃描邏輯流程圖
- 首先通過ResourcePatternResolver獲得指定包路徑下所有的class文件,并且包裝成Resource
- 遍歷每Resource對象
- 利用ASM技術(shù)解析每一個文件,得到對應的類元信息,封裝成MetadataReader
- 用excludeFilter跟includeFilter,以及@Conditionnal注解進行篩選過濾
- 篩選通過后,基于metadataReader生成ScannedGenericBeanDefinition
- 再基于metadataReader判斷是不是對應的類是不是獨立類,接口或抽象類
- 如果篩選通過,那么就表示掃描到了一個Bean,將ScannedGenericBeanDefinition加入結(jié)果集
四、合并BeanDefinition
到了后面的IOC過程,生成Bean的時候,我們會看到很多這樣的調(diào)用:
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
這個就是所謂的,獲取合并BeanDefinition。什么是合并BeanDefinition?其實就是父子BeanDefinition。跟Java里面的繼承是一樣一樣的。但是,這個通常發(fā)生在xml配置bean里面,如下:文章來源:http://www.zghlxwxcb.cn/news/detail-647212.html
<bean id="parent" class="com.zhouyu.service.Parent" scope="prototype"/>
<bean id="child" class="com.zhouyu.service.Child"/>
但是這么定義的情況下,child就是原型Bean了。因為child的父BeanDefinition是parent,所以會繼承parent上所定義的scope屬性。而在根據(jù)child來生成Bean對象之前,需要進行BeanDefinition的合并,得到完整的child的BeanDefinition。文章來源地址http://www.zghlxwxcb.cn/news/detail-647212.html
學習總結(jié)
- 學習了Spring源碼流程中的【掃描】底層原理
到了這里,關(guān)于【Spring專題】Spring之Bean的生命周期源碼解析——階段一(掃描生成BeanDefinition)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!