日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
深度解析@DependsOn注解

一、學習指引

Spring創(chuàng)建Bean時如何指定Bean的依賴順序呢?

創(chuàng)新互聯(lián)建站專業(yè)為企業(yè)提供大渡口網(wǎng)站建設(shè)、大渡口做網(wǎng)站、大渡口網(wǎng)站設(shè)計、大渡口網(wǎng)站制作等企業(yè)網(wǎng)站建設(shè)、網(wǎng)頁設(shè)計與制作、大渡口企業(yè)網(wǎng)站模板建站服務,十年大渡口做網(wǎng)站經(jīng)驗,不只是建網(wǎng)站,更提供有價值的思路和整體網(wǎng)絡服務。

在實際開發(fā)項目的過程中,經(jīng)常會遇到這樣一種場景:在開發(fā)一個A功能模塊時,這個A功能模塊可能會依賴另一個B功能模塊。此時,就需要先開發(fā)B功能模塊,然后在開發(fā)A功能模塊,在A功能模塊中調(diào)用B功能模塊的功能。

在Spring中創(chuàng)建Bean對象也是如此,可以通過某種方式指定Spring中創(chuàng)建Bean的依賴順序,Spring會根據(jù)創(chuàng)建Bean的依賴順序來創(chuàng)建對應的Bean對象。這個指定創(chuàng)建Bean依賴順序的注解就是@DependsOn注解。

本章,就一起深入探討下Spring的@DependsOn注解。

二、注解說明

關(guān)于@DependsOn注解的一點點說明~~

@DependsOn注解是Spring中提供的一個指定Spring創(chuàng)建Bean的依賴順序的注解。例如,在Spring中需要創(chuàng)建A對象和B對象,可以使用@DependsOn注解指定創(chuàng)建A對象時依賴B對象,此時,在Spring中就會先創(chuàng)建B對象,然后再創(chuàng)建A對象。

2.1 注解源碼

@DependsOn注解可以標注到類或方法上,可以控制bean的創(chuàng)建、初始化和銷毀方法的執(zhí)行順序。源碼詳見:org.springframework.context.annotation.DependsOn。

/**
* @author Juergen Hoeller
* @since 3.0
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DependsOn {
String[] value() default {};
}

從@DependsOn注解的源碼可以看出,@DependsOn注解是從Spring 3.0版本開始提供的注解。其中,只提供了一個String數(shù)組類型的value屬性,含義如下所示。

  • value:表示指定的Bean的唯一標識,被指定的Bean會在Spring創(chuàng)建當前Bean之前被創(chuàng)建。

2.2 注解使用場景

@DependsOn注解主要用于指定當前Bean對象所依賴的其他Bean對象。Spring在創(chuàng)建當前Bean之前,會先創(chuàng)建由@DependsOn注解指定的依賴Bean,在Spring中使用@DependsOn注解的場景通常會有以下幾種場景:

(1)在某些情況下,Bean不是通過屬性或構(gòu)造函數(shù)參數(shù)顯式依賴于另一個Bean的,但是卻需要在創(chuàng)建一個Bean對象之前,需要先創(chuàng)建另一個Bean對象,此時就可以使用@DependsOn注解。

(2)在單例Bean的情況下@DependsOn既可以指定初始化依賴順序,也可以指定Bean相應的銷毀執(zhí)行順序。

(3)@DependsOn注解可標注到任何直接或間接帶有@Component注解的Bean或標注到@Bean注解的方法上,可以控制Bean的創(chuàng)建、初始化和銷毀方法執(zhí)行順序。

(4)觀察者模式可以分為事件,事件源和監(jiān)聽器三個組件,如果在Spring中需要實現(xiàn)觀察者模式時,就可以使用@DependsOn注解實現(xiàn)監(jiān)聽器的Bean對象在事件源的Bean對象之前被創(chuàng)建。

三、使用案例

@DependsOn注解案例實戰(zhàn)~~

Spring的@DependsOn注解可以標注到類或方法上,所以,本節(jié),會列舉@DependsOn注解標注到類和方法上兩個案例。

3.1 標注到類上的案例

本節(jié),主要使用@DependsOn注解標注到類上來實現(xiàn)Spring創(chuàng)建Bean的依賴順序案例,具體實現(xiàn)步驟如下所示。

(1)新建DependsOnClassA類

DependsOnClassA類的源碼詳見:spring-annotation-chapter-07工程下的io.binghe.spring.annotation.chapter07.bean.DependsOnClassA。

@Component(value = "dependsOnClassA")
@DependsOn(value = {"dependsOnClassB"})
public class DependsOnClassA {
private final Logger logger = LoggerFactory.getLogger(DependsOnClassA.class);
public DependsOnClassA(){
logger.info("執(zhí)行DependsOnClassA的構(gòu)造方法");
}
}

可以看到,DependsOnClassA類上使用@Component注解標注,并且指定了Bean的名稱為dependsOnClassA,以及使用@DependsOn注解指定了依賴的Bean名稱為dependsOnClassB。

(2)新建DependsOnClassB類

DependsOnClassB類的源碼詳見:spring-annotation-chapter-07工程下的io.binghe.spring.annotation.chapter07.bean.DependsOnClassB。

@Component(value = "dependsOnClassB")
public class DependsOnClassB {
private final Logger logger = LoggerFactory.getLogger(DependsOnClassB.class);
public DependsOnClassB(){
logger.info("執(zhí)行DependsOnClassB的構(gòu)造方法");
}
}

可以看到,在DependsOnClassB類上標注了@Component注解,指定了Bean對象的名稱為dependsOnClassB。

由DependsOnClassA類和DependsOnClassB類可以看出,在Spring中創(chuàng)建DependsOnClassA類的對象時,會依賴DependsOnClassB類的對象。所以,在Spring中,創(chuàng)建DependsOnClassA類的對象之前,會先創(chuàng)建DependsOnClassB類的對象。

(3)新建DependsOnConfig類

DependsOnConfig類的源碼詳見:spring-annotation-chapter-07工程下的io.binghe.spring.annotation.chapter07.config.DependsOnConfig。

@Configuration
@ComponentScan(basePackages = "io.binghe.spring.annotation.chapter07")
public class DependsOnConfig {
}

可以看到,DependsOnConfig類的實現(xiàn)比較簡單,在DependsOnConfig類上標注了@Configuration注解,表示這是一個Spring的配置類,并且使用@ComponentScan注解指定了掃描的基礎(chǔ)包名。

(4)新建DependsOnTest類

DependsOnTest類的源碼詳見:spring-annotation-chapter-07工程下的io.binghe.spring.annotation.chapter07.DependsOnTest。

public class DependsOnTest {
public static void main(String[] args) {
new AnnotationConfigApplicationContext(DependsOnConfig.class);
}
}

可以看到,DependsOnTest類作為測試案例的啟動類,整體實現(xiàn)比較簡單,就是在main()方法中創(chuàng)建Spring的IOC容器。

(5)測試DependsOnTest類

運行DependsOnTest類中的main()方法,輸出的結(jié)果信息如下所示。

14:56:17.977 [main] INFO DependsOnClassB - 執(zhí)行DependsOnClassB的構(gòu)造方法
14:56:17.978 [main] INFO DependsOnClassA - 執(zhí)行DependsOnClassA的構(gòu)造方法

可以看到,當@DependsOn注解標注到類上時,Spring在創(chuàng)建標注了@DependsOn注解的類的Bean對象之前,會先創(chuàng)建使用@DependsOn注解指定的Bean對象。

3.2 標注到方法上的案例

本節(jié),主要使用@DependsOn注解標注到方法上來實現(xiàn)Spring創(chuàng)建Bean的依賴順序案例,并且本節(jié)的案例程序是在3.1節(jié)的基礎(chǔ)上擴展,具體實現(xiàn)步驟如下所示。

(1)新建DependsOnMethodA類

DependsOnMethodA類的源碼詳見:spring-annotation-chapter-07工程下的io.binghe.spring.annotation.chapter07.bean.DependsOnMethodA。

public class DependsOnMethodA {
private final Logger logger = LoggerFactory.getLogger(DependsOnMethodA.class);
public DependsOnMethodA(){
logger.info("執(zhí)行DependsOnMethodA的構(gòu)造方法");
}
}

可以看到,DependsOnMethodA類就是一個簡單的實體類,這里不再贅述。

(2)新增DependsOnMethodB類

DependsOnMethodB類的源碼詳見:spring-annotation-chapter-07工程下的io.binghe.spring.annotation.chapter07.bean.DependsOnMethodB。

public class DependsOnMethodB {
private final Logger logger = LoggerFactory.getLogger(DependsOnMethodB.class);
public DependsOnMethodB(){
logger.info("執(zhí)行DependsOnMethodB的構(gòu)造方法");
}
}

可以看到,DependsOnMethodB類就是一個簡單的實體類,這里不再贅述。

(3)修改DependsOnConfig類

在DependsOnConfig類中使用@Bean注解分別創(chuàng)建DependsOnMethodA類和DependsOnMethodB類的Bean對象,如下所示。

@DependsOn(value = {"dependsOnMethodB"})
@Bean(value = "dependsOnMethodA")
public DependsOnMethodA dependsOnMethodA(){
return new DependsOnMethodA();
}

@Bean(value = "dependsOnMethodB")
public DependsOnMethodB dependsOnMethodB(){
return new DependsOnMethodB();
}

可以看到,在DependsOnConfig類中使用@Bean注解創(chuàng)建DependsOnMethodA類的Bean對象時,使用@DependsOn注解依賴了名稱為dependsOnMethodB的Bean對象。

(4)測試DependsOnTest類

運行DependsOnTest類中的main()方法,輸出的結(jié)果信息如下所示。

15:16:24.523 [main] INFO DependsOnClassB - 執(zhí)行DependsOnClassB的構(gòu)造方法
15:16:24.524 [main] INFO DependsOnClassA - 執(zhí)行DependsOnClassA的構(gòu)造方法
15:16:24.528 [main] INFO DependsOnMethodB - 執(zhí)行DependsOnMethodB的構(gòu)造方法
15:16:24.529 [main] INFO DependsOnMethodA - 執(zhí)行DependsOnMethodA的構(gòu)造方法

可以看到,當@DependsOn注解標注到方法上時,Spring在執(zhí)行標注了@DependsOn注解的方法創(chuàng)建Bean對象前,先執(zhí)行其他方法來創(chuàng)建使用@DependsOn注解指定的Bean對象。

通過上述兩個案例得知:@DependsOn注解可以指定Spring中Bean對象創(chuàng)建的依賴順序,并且Spring在創(chuàng)建當前Bean之前,會先創(chuàng)建由@DependsOn注解指定的依賴Bean

四、源碼時序圖

結(jié)合時序圖理解源碼會事半功倍,你覺得呢?

本節(jié),就以源碼時序圖的方式,直觀的感受下@DependsOn注解在Spring源碼層面的執(zhí)行流程。本節(jié),主要從注冊Bean、調(diào)用Bean工廠后置處理器和創(chuàng)建Bean三個方面分析源碼時序圖。

4.1 注冊Bean的源碼時序圖

@DependsOn注解涉及到的注冊Bean的源碼時序圖如圖7-1所示。

由圖7-1可以看出,@DependsOn注解在注冊Bean的流程中涉及到DependsOnTest類、AnnotationConfigApplicationContext類、AnnotatedBeanDefinitionReader類、AnnotationConfigUtils類、BeanDefinitionReaderUtils類和DefaultListableBeanFactory類。具體的源碼執(zhí)行細節(jié)參見源碼解析部分。

4.2 調(diào)用Bean工廠后置處理器的源碼時序圖

@DependsOn注解涉及到的調(diào)用Bean工廠后置處理器的源碼時序圖如圖7-2~7-4所示。

由圖7-2~7-4可以看出,@DependsOn注解涉及到的調(diào)用Bean工廠后置處理器的流程涉及到DependsOnTest類、AnnotationConfigApplicationContext類、AbstractApplicationContext類、PostProcessorRegistrationDelegate類、ConfigurationClassPostProcessor類、ConfigurationClassParser類、ComponentScanAnnotationParser類、ClassPathBeanDefinitionScanner類、AnnotationConfigUtils類、BeanDefinitionReaderUtils類和DefaultListableBeanFactory類。具體的源碼執(zhí)行細節(jié)參見源碼解析部分。

4.3 創(chuàng)建Bean的源碼時序圖

@DependsOn注解涉及到的創(chuàng)建Bean的源碼時序圖如圖7-5所示。

由圖7-5可以看出,@DependsOn注解涉及到的創(chuàng)建Bean的流程涉及到DependsOnTest類、AnnotationConfigApplicationContext類、AbstractApplicationContext類、DefaultListableBeanFactory類和AbstractBeanFactory類。具體的源碼執(zhí)行細節(jié)參見源碼解析部分。

五、源碼解析

源碼時序圖整清楚了,那就整源碼解析唄!

本節(jié),主要分析@DependsOn注解在Spring源碼層面的執(zhí)行流程,結(jié)合源碼執(zhí)行的時序圖,會理解的更加深刻。本節(jié),同樣會從注冊Bean、調(diào)用Bean工廠后置處理器和創(chuàng)建Bean三個方面分析源碼的執(zhí)行流程

5.1 注冊Bean的源碼流程

@DependsOn注解在Spring源碼層面注冊Bean的執(zhí)行流程,結(jié)合源碼執(zhí)行的時序圖,會理解的更加深刻,本節(jié)的源碼執(zhí)行流程可以結(jié)合圖7-1進行理解。

(1)運行案例程序啟動類

案例程序啟動類源碼詳見:spring-annotation-chapter-07工程下的io.binghe.spring.annotation.chapter07.DependsOnTest,運行DependsOnTest類的main()方法。

在DependsOnTest類的main()方法中調(diào)用了AnnotationConfigApplicationContext類的構(gòu)造方法,并傳入了DependsOnConfig類的Class對象來創(chuàng)建IOC容器。接下來,會進入AnnotationConfigApplicationContext類的構(gòu)造方法。

(2)解析AnnotationConfigApplicationContext類的AnnotationConfigApplicationContext(Class... componentClasses)構(gòu)造方法

源碼詳見:org.springframework.context.annotation.AnnotationConfigApplicationContext#AnnotationConfigApplicationContext(Class... componentClasses)。

public AnnotationConfigApplicationContext(Class... componentClasses) {
this();
register(componentClasses);
refresh();
}

可以看到,在上述構(gòu)造方法中,調(diào)用了register()方法來注冊Bean。

(3)解析AnnotationConfigApplicationContext類的register(Class... componentClasses) 方法

源碼詳見:org.springframework.context.annotation.AnnotationConfigApplicationContext#register(Class... componentClasses) 。

@Override
public void register(Class... componentClasses) {
/************省略其他代碼***************/
this.reader.register(componentClasses);
registerComponentClass.end();
}

可以看到,在AnnotationConfigApplicationContext類的register()方法中,調(diào)用reader對象的register()方法注冊Bean。

(4)解析AnnotatedBeanDefinitionReader類的register(Class... componentClasses)方法

源碼詳見:org.springframework.context.annotation.AnnotatedBeanDefinitionReader#register(Class... componentClasses)。

public void register(Class... componentClasses) {
for (Class componentClass : componentClasses) {
registerBean(componentClass);
}
}

可以看到,在AnnotatedBeanDefinitionReader類的register()方法中,會循環(huán)遍歷傳入的componentClasses數(shù)組,并將遍歷出的每個componentClass元素作為參數(shù)調(diào)用registerBean()方法注冊Bean。

(5)解析AnnotatedBeanDefinitionReader類的registerBean(Class beanClass)方法

源碼詳見:org.springframework.context.annotation.AnnotatedBeanDefinitionReader#registerBean(Class beanClass)。

public void registerBean(Class beanClass) {
doRegisterBean(beanClass, null, null, null, null);
}

可以看到,在AnnotatedBeanDefinitionReader類的registerBean()方法中會調(diào)用doRegisterBean()方法來注冊Bean。

(6)解析AnnotatedBeanDefinitionReader類的doRegisterBean(ClassbeanClass, String name, Class[] qualifiers, Suppliersupplier, BeanDefinitionCustomizer[] customizers)方法

源碼詳見:org.springframework.context.annotation.AnnotatedBeanDefinitionReader#doRegisterBean(ClassbeanClass, String name, Class[] qualifiers, Suppliersupplier, BeanDefinitionCustomizer[] customizers)。重點關(guān)注如下代碼片段。

private  void doRegisterBean(Class beanClass, @Nullable String name, @Nullable Class[] qualifiers, @Nullable Supplier supplier, @Nullable BeanDefinitionCustomizer[] customizers) {
/******************省略其他代碼**********************/
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
/******************省略其他代碼**********************/
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}

可以看到,在AnnotatedBeanDefinitionReader類的doRegisterBean()方法中,會調(diào)用AnnotationConfigUtils類的processCommonDefinitionAnnotations()方法。

(7)解析AnnotationConfigUtils類的processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd)方法

源碼詳見:org.springframework.context.annotation.AnnotationConfigUtils#processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd)

public static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd) {
processCommonDefinitionAnnotations(abd, abd.getMetadata());
}

可以看到,在AnnotationConfigUtils類的processCommonDefinitionAnnotations()方法中調(diào)用了具有兩個參數(shù)的processCommonDefinitionAnnotations()方法。

(8)解析AnnotationConfigUtils類的processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata)方法

源碼詳見:org.springframework.context.annotation.AnnotationConfigUtils#processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata)。

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"));
}
}

可以看到,在processCommonDefinitionAnnotations()方法中,解析了@DependsOn注解,并將解析出的@DependsOn注解中的value屬性的值設(shè)置到AnnotatedBeanDefinition對象的dependsOn屬性中。

(9)回到AnnotatedBeanDefinitionReader類的doRegisterBean(ClassbeanClass, String name, Class[] qualifiers, Suppliersupplier, BeanDefinitionCustomizer[] customizers)方法。

在AnnotatedBeanDefinitionReader類的doRegisterBean()方法中,會調(diào)用BeanDefinitionReaderUtils類的registerBeanDefinition()方法,并將封裝了@DependsOn注解屬性的abd對象和beanName封裝成BeanDefinitionHolder對象,并且與registry一起作為參數(shù)傳遞給BeanDefinitionReaderUtils類的registerBeanDefinition()方法。

(10)解析BeanDefinitionReaderUtils類的registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)方法

源碼詳見:org.springframework.beans.factory.support.BeanDefinitionReaderUtils#registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)。

public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {
String beanName = definitionHolder.getBeanName();
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}

可以看到,在registerBeanDefinition()方法中,會調(diào)用DefaultListableBeanFactory類的registerBeanDefinition()方法將BeanDefinition信息注冊到IOC容器中。

(11)解析DefaultListableBeanFactory類的registerBeanDefinition(String beanName, BeanDefinition beanDefinition)方法

源碼詳見:org.springframework.beans.factory.support.DefaultListableBeanFactory#registerBeanDefinition(String beanName, BeanDefinition beanDefinition)。重點關(guān)注如下代碼片段。

@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException {
/*********省略其他代碼**********/
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
if (existingDefinition != null) {
/*********省略其他代碼**********/
}
else {
/*********省略其他代碼**********/
else {
// Still in startup registration phase
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
removeManualSingletonName(beanName);
}
this.frozenBeanDefinitionNames = null;
}
/*********省略其他代碼**********/
}

可以看到,在DefaultListableBeanFactory類的registerBeanDefinition()方法中,會將beanName為Key,beanDefinition對象作為Value保存到beanDefinitionMap中。

至此,@DependsOn注解涉及到的注冊Bean的源碼流程分析完畢。

5.2 調(diào)用Bean工廠后置處理器的源碼流程

@DependsOn注解在Spring源碼層面調(diào)用Bean工廠后置處理器的執(zhí)行流程,結(jié)合源碼執(zhí)行的時序圖,會理解的更加深刻,本節(jié)的源碼執(zhí)行流程可以結(jié)合圖7-2~7-4進行理解。

注意:@DependsOn注解在Spring源碼層面調(diào)用Bean工廠后置處理器的執(zhí)行流程,執(zhí)行到ConfigurationClassParser類的doProcessConfigurationClass()方法之前的邏輯與第5章解析@Import注解的代碼流程相同,這里不再贅述。后續(xù)的代碼流程直接從ConfigurationClassParser類的doProcessConfigurationClass()方法開始解析。

(1)解析ConfigurationClassParser類的doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass, Predicatefilter)方法

源碼詳見:org.springframework.context.annotation.ConfigurationClassParser#doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass, Predicatefilter),重點關(guān)注如下代碼片段。

protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass, Predicate filter) throws IOException {
/****************省略其他代碼****************/
Set componentScans = AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
if (!componentScans.isEmpty() &&
!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
for (AnnotationAttributes componentScan : componentScans) {
Set scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
/****************省略其他代碼****************/
return null;
}

可以看到,在ConfigurationClassParser類的doProcessConfigurationClass()方法中,會調(diào)用componentScanParser的parse()方法來解析配置類上的注解。

(2)解析ComponentScanAnnotationParser類的parse(AnnotationAttributes componentScan, String declaringClass)方法

源碼詳見:org.springframework.context.annotation.ComponentScanAnnotationParser#parse(AnnotationAttributes componentScan, String declaringClass)。

public Set parse(AnnotationAttributes componentScan, String declaringClass) {
/***********省略其他代碼*************/
return scanner.doScan(StringUtils.toStringArray(basePackages));
}

可以看到,在ComponentScanAnnotationParser類的parse()方法中,會調(diào)用scanner對象的doScan()方法掃描@ComponentScan注解中basePackages屬性設(shè)置的包名。

(3)解析ClassPathBeanDefinitionScanner類中的doScan(String... basePackages)方法

源碼詳見:org.springframework.context.annotation.ClassPathBeanDefinitionScanner#doScan(String... basePackages)。

protected Set doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
Set beanDefinitions = new LinkedHashSet<>();
for (String basePackage : basePackages) {
Set candidates = findCandidateComponents(basePackage);
for (BeanDefinition candidate : candidates) {
/************省略其他代碼************/
if (candidate instanceof AnnotatedBeanDefinition) {
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
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;
}

可以看到,在ClassPathBeanDefinitionScanner類中的doScan()方法中,會調(diào)用AnnotationConfigUtils類的processCommonDefinitionAnnotations()方法來解析注解的信息。后續(xù)的執(zhí)行流程與5.1節(jié)中源碼解析的步驟(7)~(8)相同,這里不再贅述。

另外,在ClassPathBeanDefinitionScanner類中的doScan()方法中,會調(diào)用registerBeanDefinition()方法來注冊BeanDefinition信息。

(4)解析ClassPathBeanDefinitionScanner類的registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)方法

源碼詳見:org.springframework.context.annotation.ClassPathBeanDefinitionScanner#registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)。

protected void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) {
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, registry);
}

可以看到,在ClassPathBeanDefinitionScanner類的registerBeanDefinition()方法中,直接調(diào)用了BeanDefinitionReaderUtils類的registerBeanDefinition()方法來注冊BeanDefinition信息。

(5)解析BeanDefinitionReaderUtils類的registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)方法

源碼詳見:org.springframework.beans.factory.support.BeanDefinitionReaderUtils#registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)。

public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)throws BeanDefinitionStoreException {
String beanName = definitionHolder.getBeanName();
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
/*********省略其他代碼************/
}

可以看到,在BeanDefinitionReaderUtils類的registerBeanDefinition()方法中,最終就會調(diào)用DefaultListableBeanFactory類的registerBeanDefinition()方法來注冊BeanDefinition信息。

至此,@DependsOn注解在Spring源碼層面調(diào)用Bean工廠后置處理器的執(zhí)行流程分析完畢。

5.3 創(chuàng)建Bean的源碼流程

@DependsOn注解在Spring源碼層面創(chuàng)建Bean的執(zhí)行流程,結(jié)合源碼執(zhí)行的時序圖,會理解的更加深刻,本節(jié)的源碼執(zhí)行流程可以結(jié)合圖7-5進行理解。

注意:@DependsOn注解在Spring源碼層面創(chuàng)建Bean的執(zhí)行流程,執(zhí)行到AbstractApplicationContext類的refresh()方法的邏輯,與第5章解析@Import注解執(zhí)行到AbstractApplicationContext類的refresh()方法的邏輯相同,這里不再贅述。后續(xù)會直接從AbstractApplicationContext類的refresh()方法開始分析源碼。

(1)解析AbstractApplicationContext類的refresh()方法

源碼詳見:org.springframework.context.support.AbstractApplicationContext#refresh(),重點關(guān)注如下代碼片段。

@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
/*********省略其他代碼************/
try {
/*********省略其他代碼************/
finishBeanFactoryInitialization(beanFactory);
/*********省略其他代碼************/
}
catch (BeansException ex) {
/*********省略其他代碼************/
}
finally {
/*********省略其他代碼************/
}
}
}

可以看到,在refresh()中會調(diào)用finishBeanFactoryInitialization()方法來完成非懶加載的單實例Bean的初始化工作。

(2)解析finishBeanFactoryInitialization類的finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory)方法

源碼詳見:org.springframework.context.support.AbstractApplicationContext#finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory)。

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
/*******省略其他代碼*******/
beanFactory.preInstantiateSingletons();
}

可以看到,在finishBeanFactoryInitialization類的finishBeanFactoryInitialization()方法中,會調(diào)用beanFactory對象的preInstantiateSingletons()方法來初始化所有的非懶加載的單實例Bean。

(3)解析DefaultListableBeanFactory類的preInstantiateSingletons()方法

源碼詳見:org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons()。重點關(guān)注如下代碼片段。

@Override
public void preInstantiateSingletons() throws BeansException {
/*********省略其他代碼*********/
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof SmartFactoryBean smartFactoryBean && smartFactoryBean.isEagerInit()) {
getBean(beanName);
}
}
else {
getBean(beanName);
}
}
}
/*********省略其他代碼*********/
}

可以看到,在DefaultListableBeanFactory類的preInstantiateSingletons()方法中,會遍歷beanDefinitionNames集合中所有的beanName,并調(diào)用getBean()方法初始化所有非懶加載的單實例Bean。

(4)解析AbstractBeanFactory類的getBean(String name)方法

源碼詳見:org.springframework.beans.factory.support.AbstractBeanFactory#getBean(String name)。

@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}

可以看到,在AbstractBeanFactory類的getBean()方法中,直接調(diào)用了doGetBean()方法來初始化非懶加載的單實例Bean。

(5)解析AbstractBeanFactory類的doGetBean(String name, ClassrequiredType, Object[] args, boolean typeCheckOnly)方法

源碼詳見:org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean(String name, ClassrequiredType, Object[] args, boolean typeCheckOnly)。重點關(guān)注如下代碼片段。

protected  T doGetBean(String name, @Nullable Class requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {
/*************省略其他代碼**************/
else {
/*************省略其他代碼**************/
try {
/*************省略其他代碼**************/
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
registerDependentBean(dep, beanName);
try {
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
/*************省略其他代碼**************/
}
catch (BeansException ex) {
beanCreation.tag("exception", ex.getClass().toString());
beanCreation.tag("message", String.valueOf(ex.getMessage()));
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
finally {
beanCreation.end();
}
}
return adaptBeanInstance(name, beanInstance, requiredType);
}

可以看到,在AbstractBeanFactory類的doGetBean()方法中,會獲取這些被依賴的beanName,按照數(shù)組順序,再調(diào)用AbstractBeanFactory類的getBean()方法來優(yōu)先創(chuàng)建被依賴的Bean,從而達到控制依賴順序的目的。

另外,在創(chuàng)
當前名稱:深度解析@DependsOn注解
鏈接地址:http://www.dlmjj.cn/article/dhsojgs.html