spring被@Bean注解的方法是如何变成SpringBean

2020-07-01  本文已影响0人  黑铁大魔王

概述一下

springframework有很多创建SpringBean的方式,所谓SpringBean就是被spring生命周期管理的bean。比如@Component,@Service等注解的Class,在Spring启动时,都会逐步生成SpringBean,并且被spring容器管理。
在@Configuration注解的配置类里,通过被@Bean注解的方法,也能生成SpringBean。
如:

@Configuration
@ComponentScan("org.dhframework")
public class Appconfig {
    @Bean
    public WanDouBean xyz() {
        System.out.println("通过xyz()创建WanDouBean");
        return new WanDouBean();
    }
}

分析一下

把一个类纳入spring来管理,需要主要2个大步骤(个人理解这2个步骤很重要)。
第一,生成这个类相关的BeanDefinition(bd),把该bd放到BeanDefinitionMap(bdMap)里。
第二,从bdMap把该bd捞出啦,然后生成SpringBean,放入singletonObjects(是个map)里。

  1. 如何生成bd?
    AbstractApplicationContext类里的refresh方法
@Override
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // Prepare this context for refreshing.
            prepareRefresh();

            // Tell the subclass to refresh the internal bean factory.
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // Prepare the bean factory for use in this context.
            prepareBeanFactory(beanFactory);

            try {
                // Allows post-processing of the bean factory in context subclasses.
                postProcessBeanFactory(beanFactory);

                // Invoke factory processors registered as beans in the context.
                // 这里是根据扫描到的class生成bd的方法,跟进去看即可
                invokeBeanFactoryPostProcessors(beanFactory);

                // Register bean processors that intercept bean creation.
                registerBeanPostProcessors(beanFactory);

                // Initialize message source for this context.
                initMessageSource();

                // Initialize event multicaster for this context.
                initApplicationEventMulticaster();

                // Initialize other special beans in specific context subclasses.
                onRefresh(); // springboot依赖starter-web后,里会进入AbstractApplicationContext子类AnnotationConfigServletWebServerApplicationContext里的onRefresh(),进而启动web容器

                // Check for listener beans and register them.
                registerListeners();

                // Instantiate all remaining (non-lazy-init) singletons.
                finishBeanFactoryInitialization(beanFactory);

                // Last step: publish corresponding event.
                finishRefresh();
            }
。。。

上面代码里有个invokeBeanFactoryPostProcessors(beanFactory);调用,bd的生成与管理就是在这里被执行的。
一路跟下来,会进入PostProcessorRegistrationDelegate类的下面方法

public static void invokeBeanFactoryPostProcessors(
            ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) 

该方法里,会调用invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);,这里的两个参数
· currentRegistryProcessors:是ConfigurationClassPostProcessor
· registry:是beanFactory,也就是DefaultListableBeanFactory
进入该方法,那当然就是用ConfigurationClassPostProcessor后置处理器来处理DefaultListableBeanFactory的对象beanFactory咯。
经过一次调用之后,会来到ConfigurationClassPostProcessor的public void processConfigBeanDefinitions(BeanDefinitionRegistry registry)方法里,该方法里会拿到registry里的bdNames列表(框架提供的5个类的bd与@Configuration注解类的bd),然后遍历该列表拿到bd对象,再然后经过一些有的没的,跟我们这次核心有关,但是不需要太关注的步骤之后。就来到this.reader.loadBeanDefinitions(configClasses);,这里·reader:是ConfigurationClassBeanDefinitionReader对象,configClasses是程序员自定义的组建类的ConfigurationClass对象列表(@Component,@Service,等注解的,包括@Configuration),自然就是要通过reader来读这些类了

image.png
那么,非框架类的Class在生成生成bd之前,会先被包装成ConfigurationClass,然后通过reader来处理(loadBeanDefinitions)。
image.png
显然,这里有多个configurationClass对象等待处理,但是因为咱们要跟踪的是通过@Bean注解的方法生成bd的过程,所以只看@Configuration注解的类,也就是AppConfig的loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);调用。
好吧,大宝贝来了
大宝贝
这个截图我在写@Import注解是也用过,@Import与@Bean到此出的流程都一样。好了继续说@Bean
beanMethod 。可以看出通过configClass对象拿到的beanMethod对象,这就是AppConfig代码里写的@Bean xyz()方法。
继续跟进去,会来到private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod)方法里,这里会根据beanMethod拿到methodName,然后赋值给beanName。
在搞一个ConfigurationClassBeanDefinition的对象beanDef出来。
ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata);

再给beanDef对象设置属性,@Bean的默认几个属性
autowire, autowireCandidate, initMethod, destroyMethod, value,这几个属性都是在定义@Bean注解方法返回类里面加注解生成的。
还有resource,source属性的设置。
接下来,碎碎叨叨就注册了。
注册时的beanDef截图如下


image.png image.png

在注册到bdMap时,beanDef里的属性如上图,重要的一些属性由箭头指出
比如MateData里的内省方法等,source,resource,factoryMethodName,factoryBeanName等等。这些属性都会影响到后面生成SpringBean的操作。

上一篇 下一篇

猜你喜欢

热点阅读