日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

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

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
我們深度解析@Bean注解,你學(xué)會(huì)了嗎?

大家好,我是冰河~~

「本章難度」:

「本章重點(diǎn)」:進(jìn)一步了解@Bean注解的使用方法和如何避免踩坑,并在源碼級(jí)別徹底理解和吃透@Bean注解的執(zhí)行流程。

一、學(xué)習(xí)指引

@Bean注解的實(shí)現(xiàn)其實(shí)沒你想象的那么簡單!

翻看Spring的源碼時(shí),發(fā)現(xiàn)@Bean注解的源碼上標(biāo)注了Since: 3.0,也就是說,@Bean注解是Spring從3.0版本開始提供的源碼。@Bean注解可以標(biāo)注在方法上,將當(dāng)前方法的返回值注入到IOC容器中,也可以標(biāo)注到注解上,作為元注解使用。

還是那句話:如果只想做CRUD程序員,對(duì)于@Bean注解了解到這里就已經(jīng)可以了,如果想進(jìn)一步突破自己,讓自己的技術(shù)能力更上一層樓,則繼續(xù)往下看。

二、注解說明

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

@Bean注解可以說是使用Spring開發(fā)應(yīng)用程序時(shí),使用的比較多的一個(gè)注解,尤其是基于SpringBoot開發(fā)應(yīng)用程序時(shí),@Bean注解使用的就很多了。@Bean注解可以標(biāo)注到方法上,將當(dāng)前方法的返回值注入到IOC容器中。@Bean注解也可以標(biāo)注到注解上,作為元注解使用。

2.1 注解源碼

本節(jié),主要對(duì)@Bean注解的源碼進(jìn)行簡單的剖析。

@Bean注解的源碼詳見:org.springframework.context.annotation.Bean,如下所示。

/**
* @author Rod Johnson
* @author Costin Leau
* @author Chris Beams
* @author Juergen Hoeller
* @author Sam Brannen
* @since 3.0
*/
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Bean {
//Since: 4.3.3
@AliasFor("name")
String[] value() default {};

@AliasFor("value")
String[] name() default {};

//Since: 5.1
boolean autowireCandidate() default true;

String initMethod() default "";

String destroyMethod() default AbstractBeanDefinition.INFER_METHOD;
}

從@Bean源碼的注釋可以看出,@Bean注解是Spring從3.0版本開始提供的注解,注解中各個(gè)屬性的含義如下所示。

name:String[]數(shù)組類型,指定注入到IOC容器中的Bean的名稱,可以指定多個(gè)名稱。如果不指定name屬性和value屬性的值,則注入到IOC容器中的Bean的名稱默認(rèn)是方法的名稱。

value:String[]數(shù)組類型,從Spring 4.3.3版本開始提供的@Bean的屬性,作用與name屬性相同。

autowireCandidate:boolean類型,表示是否支持自動(dòng)按照類型注入到其他的Bean中。此屬性會(huì)影響@Autowired注解,不會(huì)響應(yīng)@Resource注解,默認(rèn)為true,表示支持自動(dòng)按照類型注入到其他的Bean中。

initMethod:指定初始化的方法。

destroyMethod:指定銷毀的方法。

2.2 注解使用場景

在使用Spring的注解開發(fā)應(yīng)用程序時(shí),如果是我們自己開發(fā)的類,可以在類上標(biāo)注@Component注解(也可以是@Repository、@Service、@Controller等注解),將類注入到IOC容器中。但是,有時(shí)很多類不是我們自己寫的,而是依賴的第三方的類庫,此時(shí)就無法在類上標(biāo)注@Component等注解了,此時(shí)就需要使用@Bean注解將其注入到IOC容器中。

也就是說,@Bean注解適用于將第三方提供的類注入到IOC容器中的場景。使用@Bean注解創(chuàng)建的Bean對(duì)象默認(rèn)是單實(shí)例Bean對(duì)象。

三、使用案例

整個(gè)案例來玩玩兒吧!

3.1 案例描述

使用@Bean注解將User類的對(duì)象注入到IOC容器中,打印初始化和銷毀方法,并驗(yàn)證使用@Bean注解創(chuàng)建的Bean對(duì)象默認(rèn)是單實(shí)例Bean。

3.2 案例實(shí)現(xiàn)

使用@Bean注解可以將類對(duì)象注入到IOC容器中,并且@Bean注解的initMethod屬性可以指定初始化的方法,destroyMethod屬性可以指定銷毀的方法。當(dāng)IOC容器對(duì)Bean對(duì)象進(jìn)行初始化時(shí),會(huì)執(zhí)行@Bean注解的initMethod屬性指定的方法,當(dāng)IOC容器在關(guān)閉時(shí),會(huì)執(zhí)行@Bean注解的destroyMethod屬性指定的方法,觸發(fā)銷毀方法的邏輯。

注意:上述邏輯僅限于注入到IOC容器中的單例Bean對(duì)象。如果是單實(shí)例Bean,則IOC容器啟動(dòng)時(shí),就會(huì)創(chuàng)建Bean對(duì)象,IOC容器關(guān)閉時(shí),銷毀Bean對(duì)象。如果是多實(shí)例Bean,IOC容器在啟動(dòng)時(shí),不會(huì)創(chuàng)建Bean對(duì)象,在每次從IOC容器中獲取Bean對(duì)象時(shí),都會(huì)創(chuàng)建新的Bean對(duì)象返回,IOC容器關(guān)閉時(shí),也不會(huì)銷毀對(duì)象。也就是說,如果是多實(shí)例Bean,IOC容器不會(huì)管理Bean對(duì)象。

本節(jié),就以單實(shí)例Bean為例來實(shí)現(xiàn)案例程序,具體的實(shí)現(xiàn)步驟如下所示。

(1)新建注入到IOC容器中的User類

源碼詳見:spring-annotation-chapter-03工程下的io.binghe.spring.annotation.chapter03.bean.User,如下所示。

public class User {

private final Logger logger = LoggerFactory.getLogger(User.class);

public User(){
logger.info("執(zhí)行構(gòu)造方法...");
}

public void init(){
logger.info("執(zhí)行初始化方法...");
}

public void destroy(){
logger.info("執(zhí)行銷毀方法...");
}
}

IOC容器啟動(dòng)時(shí),會(huì)創(chuàng)建User類的對(duì)象并調(diào)用init()方法進(jìn)行初始化。IOC容器關(guān)閉時(shí),會(huì)銷毀User類的對(duì)象,并調(diào)用destroy()方法執(zhí)行銷毀邏輯。

可以看到,User類的實(shí)現(xiàn)比較簡單,提供了一個(gè)無參構(gòu)造方法,一個(gè)表示初始化的init()方法和一個(gè)表示銷毀的destroy()方法,每個(gè)方法中都打印了相應(yīng)的日志來說明調(diào)用了對(duì)應(yīng)的方法。

(2)創(chuàng)建Spring的配置類BeanConfig

源碼詳見:spring-annotation-chapter-03工程下的io.binghe.spring.annotation.chapter03.config.BeanConfig,如下所示。

@Configuration
@ComponentScan(basePackages = "io.binghe.spring.annotation.chapter03")
public class BeanConfig {
@Bean(initMethod = "init", destroyMethod = "destroy")
public User user(){
return new User();
}
}

可以看到,在BeanConfig類上標(biāo)注了@Configuration注解,說明BeanConfig類是一個(gè)Spring的配置類,并且在BeanConfig類上標(biāo)注了@ComponentScan注解,指定要掃描的包為io.binghe.spring.annotation.chapter03。

在BeanConfig類中定義了一個(gè)user()方法,返回一個(gè)User對(duì)象。在user()方法上標(biāo)注了@Bean注解,并通過initMethod屬性指定的初始化方法為User類的init()方法,通過destroyMethod屬性指定的銷毀方法為User類的destroy()方法。

(3)創(chuàng)建案例測試類BeanTest

源碼詳見:spring-annotation-chapter-03工程下的io.binghe.spring.annotation.chapter03.BeanTest,如下所示。

public class BeanTest {
private static final Logger LOGGER = LoggerFactory.getLogger(BeanTest.class);
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig.class);
LOGGER.info("IOC容器啟動(dòng)完成....");
User user1 = context.getBean(User.class);
User user2 = context.getBean(User.class);
LOGGER.info("user1是否等于user2===>>>{}", (user1 == user2));
context.close();
}
}

可以看到,在BeanTest類中,通過BeanConfig配置類創(chuàng)建了IOC容器,從IOC容器中兩次獲取User對(duì)象,分別賦值給user1和user2,打印user1是否等于user2的日志,并關(guān)閉IOC容器。

3.3 案例測試

運(yùn)行BeanTest類的main()方法,輸出的日志信息如下所示。

- 執(zhí)行構(gòu)造方法...
- 執(zhí)行初始化方法...
- IOC容器啟動(dòng)完成....
- user1是否等于user2===>>>true
- 執(zhí)行銷毀方法...

可以看到,IOC容器在啟動(dòng)時(shí),就創(chuàng)建了User對(duì)象,并調(diào)用了@Bean注解的initMethod方法指定的初始化方法,IOC容器在關(guān)閉時(shí),調(diào)用@Bean注解的destroyMethod屬性指定的銷毀方法。并且通過打印的user1是否等于user2的日志為true,可以說明使用@Bean注解默認(rèn)創(chuàng)建的Bean對(duì)象是單實(shí)例Bean,每個(gè)類在IOC容器中只會(huì)存在一個(gè)單實(shí)例Bean對(duì)象。

四、源碼時(shí)序圖

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

本節(jié),就以源碼時(shí)序圖的方式,直觀的感受下@Bean注解在Spring源碼層面的執(zhí)行流程。@Bean注解在Spring源碼層面的執(zhí)行流程如圖3-1和圖3-2所示。

圖3-1

圖3-2

由圖3-1和圖3-2可以看出,@Bean注解在Spring源碼層面的執(zhí)行流程會(huì)涉及到BeanTest類、AnnotationConfigApplicationContext類、AbstractApplicationContext類、PostProcessorRegistrationDelegate類、ConfigurationClassPostProcessor類、ConfigurationClassParser類、ConfigurationClassBeanDefinitionReader類和DefaultListableBeanFactory類。具體的源碼執(zhí)行細(xì)節(jié)參見源碼解析部分。

五、源碼解析

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

@Bean注解在Spring源碼層面的執(zhí)行流程,結(jié)合源碼執(zhí)行的時(shí)序圖,會(huì)理解的更加深刻。

(1)運(yùn)行案例程序啟動(dòng)類

案例程序啟動(dòng)類源碼詳見:spring-annotation-chapter-03工程下的io.binghe.spring.annotation.chapter03.BeanTest,運(yùn)行BeanTest類的main()方法。

在BeanTest類的main()方法中調(diào)用了AnnotationConfigApplicationContext類的構(gòu)造方法,并傳入了ComponentScanConfig類的Class對(duì)象來創(chuàng)建IOC容器。接下來,會(huì)進(jìn)入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)用了refresh()方法來刷新IOC容器。

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

源碼詳見:org.springframework.context.support.AbstractApplicationContext#refresh()。

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

refresh()方法是Spring中一個(gè)非常重要的方法,很多重要的功能和特性都是通過refresh()方法進(jìn)行注入的??梢钥吹?,在refresh()方法中,調(diào)用了invokeBeanFactoryPostProcessors()方法。

(4)解析AbstractApplicationContext類的invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory)方法

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

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
if (!NativeDetector.inNativeImage() && beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
}

可以看到,在AbstractApplicationContext類的invokeBeanFactoryPostProcessors()方法中調(diào)用了PostProcessorRegistrationDelegate類的invokeBeanFactoryPostProcessors()方法。

(5)解析PostProcessorRegistrationDelegate類的invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, ListbeanFactoryPostProcessors)方法

源碼詳見:org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, ListbeanFactoryPostProcessors)。

由于方法的源碼比較長,這里,只關(guān)注當(dāng)前最核心的邏輯,如下所示。

public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List beanFactoryPostProcessors) {

//############省略其他代碼##############
List currentRegistryProcessors = new ArrayList<>();

// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
currentRegistryProcessors.clear();

// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
currentRegistryProcessors.clear();

// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
boolean reiterate = true;
while (reiterate) {
reiterate = false;
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
reiterate = true;
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
currentRegistryProcessors.clear();
}
//############省略其他代碼##############
}

可以看到,在PostProcessorRegistrationDelegate類的invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, ListbeanFactoryPostProcessors)方法中,BeanDefinitionRegistryPostProcessor的實(shí)現(xiàn)類在執(zhí)行邏輯上會(huì)有先后順序,并且最終都會(huì)調(diào)用invokeBeanDefinitionRegistryPostProcessors()方法。

(6)解析PostProcessorRegistrationDelegate類的invokeBeanDefinitionRegistryPostProcessors(Collection postProcessors, BeanDefinitionRegistry registry, ApplicationStartup applicationStartup)方法

源碼詳見:org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanDefinitionRegistryPostProcessors(Collection postProcessors, BeanDefinitionRegistry registry, ApplicationStartup applicationStartup)。

private static void invokeBeanDefinitionRegistryPostProcessors(
Collection postProcessors, BeanDefinitionRegistry registry, ApplicationStartup applicationStartup) {

for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
StartupStep postProcessBeanDefRegistry = applicationStartup.start("spring.context.beandef-registry.post-process")
.tag("postProcessor", postProcessor::toString);
postProcessor.postProcessBeanDefinitionRegistry(registry);
postProcessBeanDefRegistry.end();
}
}

可以看到,在invokeBeanDefinitionRegistryPostProcessors()方法中,會(huì)循環(huán)遍歷postProcessors集合中的每個(gè)元素,調(diào)用postProcessBeanDefinitionRegistry()方法注冊Bean的定義信息。

(7)解析ConfigurationClassPostProcessor類的postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)方法

源碼詳見:org.springframework.context.annotation.ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)。

@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
//##########省略其他代碼###################
processConfigBeanDefinitions(registry);
}

可以看到,在postProcessBeanDefinitionRegistry()方法中,會(huì)調(diào)用processConfigBeanDefinitions()方法。

(8)解析ConfigurationClassPostProcessor類的processConfigBeanDefinitions(BeanDefinitionRegistry registry)方法

源碼詳見:org.springframework.context.annotation.ConfigurationClassPostProcessor#processConfigBeanDefinitions(BeanDefinitionRegistry registry)。

這里,重點(diǎn)關(guān)注方法中的如下邏輯。

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
//############省略其他代碼#################
// Parse each @Configuration class
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);

Set candidates = new LinkedHashSet<>(configCandidates);
Set alreadyParsed = new HashSet<>(configCandidates.size());
do {
StartupStep processConfig = this.applicationStartup.start("spring.context.config-classes.parse");
parser.parse(candidates);
parser.validate();
//############省略其他代碼#################
this.reader.loadBeanDefinitions(configClasses);
alreadyParsed.addAll(configClasses);
processConfig.tag("classCount", () -> String.valueOf(configClasses.size())).end();
//############省略其他代碼#################
}
while (!candidates.isEmpty());
//############省略其他代碼#################
}

可以看到,在processConfigBeanDefinitions()方法中,創(chuàng)建了一個(gè)ConfigurationClassParser類型的對(duì)象parser,并且調(diào)用了parser的parse()方法來解析類的配置信息。

(9)解析ConfigurationClassParser類的parse(SetconfigCandidates)方法

源碼詳見:org.springframework.context.annotation.ConfigurationClassParser#parse(SetconfigCandidates)。

public void parse(Set configCandidates) {
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
if (bd instanceof AnnotatedBeanDefinition) {
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
}
else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
}
else {
parse(bd.getBeanClassName(), holder.getBeanName());
}
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
}
}
this.deferredImportSelectorHandler.process();
}

可以看到,在ConfigurationClassParser類的parse(SetconfigCandidates)方法中,調(diào)用了類中的另一個(gè)parse()方法。

(10)解析ConfigurationClassParser類的parse(AnnotationMetadata metadata, String beanName)方法

源碼詳見:org.springframework.context.annotation.ConfigurationClassParser#parse(AnnotationMetadata metadata, String beanName)

protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
processConfigurationClass(new ConfigurationClass(metadata, beanName), DEFAULT_EXCLUSION_FILTER);
}

可以看到,上述parse()方法的實(shí)現(xiàn)比較簡單,直接調(diào)用了processConfigurationClass()方法。

(11)解析ConfigurationClassParser類的processConfigurationClass(ConfigurationClass configClass, Predicatefilter)方法

源碼詳見:org.springframework.context.annotation.ConfigurationClassParser#processConfigurationClass(ConfigurationClass configClass, Predicatefilter)。

protected void processConfigurationClass(ConfigurationClass configClass, Predicate filter) throws IOException {
//###############省略其他代碼####################
SourceClass sourceClass = asSourceClass(configClass, filter);
do {
sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
}
while (sourceClass != null);
this.configurationClasses.put(configClass, configClass);
}

可以看到,在processConfigurationClass()方法中,會(huì)通過do-while()循環(huán)獲取配置類和其父類的注解信息,SourceClass類中會(huì)封裝配置類上注解的詳細(xì)信息。在在processConfigurationClass()方法中,調(diào)用了doProcessConfigurationClass()方法。

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

源碼詳見:org.springframework.context.annotation.ConfigurationClassParser#doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass, Predicatefilter)。

protected final SourceClass doProcessConfigurationClass(
ConfigurationClass configClass, SourceClass sourceClass, Predicate filter)
throws IOException {
//##################省略其他代碼##################
// Process individual @Bean methods
Set beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
//##################省略其他代碼##################
// No superclass -> processing is complete
return null;
}

這里,只關(guān)注與@Bean注解相關(guān)的方法,可以看到,在doProcessConfigurationClass()方法中調(diào)用了retrieveBeanMethodMetadata()方法來解析sourceClass中有關(guān)@Bean注解的屬性信息。

(13)解析ConfigurationClassParser類的retrieveBeanMethodMetadata(SourceClass sourceClass)方法

源碼詳見:org.springframework.context.annotation.ConfigurationClassParser#retrieveBeanMethodMetadata(SourceClass sourceClass)。

private Set retrieveBeanMethodMetadata(SourceClass sourceClass) {
AnnotationMetadata original = sourceClass.getMetadata();
Set beanMethods = original.getAnnotatedMethods(Bean.class.getName());
if (beanMethods.size() > 1 && original instanceof StandardAnnotationMetadata) {
try {
AnnotationMetadata asm = this.metadataReaderFactory.getMetadataReader(original.getClassName()).getAnnotationMetadata();
Set asmMethods = asm.getAnnotatedMethods(Bean.class.getName());
if (asmMethods.size() >= beanMethods.size()) {
Set selectedMethods = new LinkedHashSet<>(asmMethods.size());
for (MethodMetadata asmMethod : asmMethods) {
for (MethodMetadata beanMethod : beanMethods) {
if (beanMethod.getMethodName().equals(asmMethod.getMethodName())) {
selectedMethods.add(beanMethod);
break;
}
}
}
if (selectedMethods.size() == beanMethods.size()) {
beanMethods = selectedMethods;
}
}
}
catch (IOException ex) {
logger.debug("Failed to read class file via ASM for determining @Bean method order", ex);
}
}
return beanMethods;
}

可以看到,在retrieveBeanMethodMetadata()方法中主要是解析@Bean注解,并且將解析到的方法元數(shù)據(jù)存入 Set集合中并返回。

(14)回到ConfigurationClassParser類的doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass, Predicatefilter)方法。

這里,還是重點(diǎn)看下方法中與@Bean注解有關(guān)的代碼片段,如下所示。

Set beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}

調(diào)用retrieveBeanMethodMetadata()方法獲取到標(biāo)注了@Bean注解的方法的元數(shù)據(jù)集合后,遍歷方法的元數(shù)據(jù)集合,將方法的元數(shù)據(jù)methodMetadata和配置類configClass傳入BeanMethod類的構(gòu)造方法,創(chuàng)建BeanMethod對(duì)象,并調(diào)用configClass的addBeanMethod()方法傳入創(chuàng)建的BeanMethod對(duì)象。

configClass的addBeanMethod()方法的源碼詳見:org.springframework.context.annotation.ConfigurationClass#addBeanMethod(BeanMethod method),如下所示。

void addBeanMethod(BeanMethod method) {
this.beanMethods.add(method);
}

可以看到,在addBeanMethod()方法中,調(diào)用了beanMethods的add()方法添加BeanMethod對(duì)象。

beanMethods的源碼詳見:org.springframework.context.annotation.ConfigurationClass#beanMethods,如下所示。

private final Set beanMethods = new LinkedHashSet<>();

可以看到,beanMethods是一個(gè)LinkedHashSet類型的集合。也就是說,在ConfigurationClassParser類的doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass, Predicatefilter)方法中,會(huì)將解析出的標(biāo)注了@Bean注解的元數(shù)據(jù)封裝成BeanMethod對(duì)象,添加到一個(gè)LinkedHashSet類型的beanMethods集合中。

(15)回到ConfigurationClassPostProcessor類的processConfigBeanDefinitions(BeanDefinitionRegistry registry)方法

源碼詳見:org.springframework.context.annotation.ConfigurationClassPostProcessor#processConfigBeanDefinitions(BeanDefinitionRegistry registry)。

此時(shí),重點(diǎn)關(guān)注下如下源碼片段。

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
//############省略其他代碼#################
do {
//############省略其他代碼#################
this.reader.loadBeanDefinitions(configClasses);
alreadyParsed.addAll(configClasses);
processConfig.tag("classCount", () -> String.valueOf(configClasses.size())).end();
//############省略其他代碼#################
}
while (!candidates.isEmpty());
//############省略其他代碼#################
}

可以看到,在processConfigBeanDefinitions()方法的do-while()循環(huán)中,調(diào)用了reader的loadBeanDefinitions()方法來加載Bean的定義信息。

(16)解析ConfigurationClassBeanDefinitionReader類的loadBeanDefinitions(SetconfigurationModel)方法

源碼詳見:org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitions(SetconfigurationModel)

public void loadBeanDefinitions(Set configurationModel) {
TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
for (ConfigurationClass configClass : configurationModel) {
loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
}
}

可以看到,在loadBeanDefinitions()方法中,會(huì)循環(huán)遍歷,傳入的configurationModel集合,并調(diào)用loadBeanDefinitionsForConfigurationClass()方法處理遍歷的每個(gè)元素。

(17)解析ConfigurationClassBeanDefinitionReader類的loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator)方法

源碼詳見:org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator)。

private void loadBeanDefinitionsForConfigurationClass(
ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
//###############省略其他代碼################
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
loadBeanDefinitionsForBeanMethod(beanMethod);
}
//###############省略其他代碼################
}

可以看到,在loadBeanDefinitionsForConfigurationClass()方法中,會(huì)循環(huán)遍歷通過configClass獲取到的BeanMethod集合,并調(diào)用loadBeanDefinitionsForBeanMethod()方法處理遍歷的每個(gè)BeanMethod對(duì)象。

(18)解析ConfigurationClassBeanDefinitionReader類的loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod)方法

源碼詳見:org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod)

private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
ConfigurationClass configClass = beanMethod.getConfigurationClass();
MethodMetadata metadata = beanMethod.getMetadata();
String methodName = metadata.getMethodName();
if (this.conditionEvaluator.shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN)) {
configClass.skippedBeanMethods.add(methodName);
return;
}
if (configClass.skippedBeanMethods.contains(methodName)) {
return;
}
AnnotationAttributes bean = AnnotationConfigUtils.attributesFor(metadata, Bean.class);
Assert.state(bean != null, "No @Bean annotation attributes");
List names = new ArrayList<>(Arrays.asList(bean.getStrin
網(wǎng)站名稱:我們深度解析@Bean注解,你學(xué)會(huì)了嗎?
文章網(wǎng)址:http://m.5511xx.com/article/cddiodo.html