Spring Boot源码:Bean装配

Posted SunSAS

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring Boot源码:Bean装配相关的知识,希望对你有一定的参考价值。

为了演示Spring中对象是如何创建并放到spring容器中,这里新建一个maven项目:

 

 

 其中pom.xm文件中只引入了一个依赖:

<dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.9.RELEASE</version>
        </dependency>
    </dependencies>

其实我们只需要这一个,不过spring还是会自动导入他别的依赖,例如spring core,spring aop:

 

 

 需要说明的是我这里并没有建spring boot项目,只是引入一个spring context依赖的maven项目。

新建一个config配置类,并没有@Configuration注解:

@ComponentScan("component")
public class MyConfig {
}

只有一个@ComponentScan注解,去扫描指定包。

新建一个类(bean),只有@Component注解:

@Component
public class People {
}

新建Test类,此类去创建spring context(spring上下文,或者说是spring容器):

import config.MyConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Test {
    public static void main(String[] args) {
        //通过注解配置类初始化 spring上下文
        AnnotationConfigApplicationContext annotationConfigApplicationContext =
                new AnnotationConfigApplicationContext(MyConfig.class);
        //还有一种通过xml来初始化 spring上下文,这里就不介绍了。
        //ClassPathXmlApplicationContext
        System.out.println(annotationConfigApplicationContext.getBean("people"));
    }
}

项目结构如图:

 

 

我们只关注bean的创建,所以在 new AnnotationConfigApplicationContext(MyConfig.class) 时会去扫描类,然后实例化。

 

 this()调用此类的构造器:

 

 这个reader和scanner和这里bean实例化没有关系,是一些扩展。我们关注他的父类构造器:

 

 可见this()方法就是建立一个beanFactory工厂,至于细节暂时不去深入。

 

 register()方法作用是新建一个BeanDefinition。

 

 BeanDefinition顾名思义就是spring定义的一个描述bean的类,这个是接口,其描述类的属性由其子类扩展,比如class,lazy(懒加载)等等:

 

 上面时AbstarctBeanDefinition类下的属性。spring根据我们的类(不管是@Service,@Controller,或者是通过@Bean方式),生成对应的BeanDefinition对象。

再把它放到一个Map中:

 

 

 

 registerBeanDefinition有三个实现方法,不管哪个都有下面这一句:

 

 即把各个BeanDefinition对象放入beanDefinitionMap中去,而这些map的集合就是spring 的容器。

所以register()做了两件事:

1:生成对应BeanDefinition对象;

2:放入beanDefinitionMap中。

最后再来看refresh()方法:

 

 这个方法是spring中最复杂也是最重要的方法:

@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.
                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();

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

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

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

            catch (BeansException ex) {
                if (logger.isWarnEnabled()) {
                    logger.warn("Exception encountered during context initialization - " +
                            "cancelling refresh attempt: " + ex);
                }

                // Destroy already created singletons to avoid dangling resources.
                destroyBeans();

                // Reset \'active\' flag.
                cancelRefresh(ex);

                // Propagate exception to caller.
                throw ex;
            }

            finally {
                // Reset common introspection caches in Spring\'s core, since we
                // might not ever need metadata for singleton beans anymore...
                resetCommonCaches();
            }
        }
    }

 其中invokeBeanFactoryPostProcessors()方法需要讲一讲,详见下一篇。

Spring Boot源码(五):BeanFactoryPostProcessor和BeanPostProcessor

以上是关于Spring Boot源码:Bean装配的主要内容,如果未能解决你的问题,请参考以下文章

使用 Spring Boot 2.1.15.RELEASE(junit 4) 进行集成测试的 Bean 自动装配为 null

Spring Boot:来自库项目的自动装配 bean

Spring boot 梳理 - 在bean中使用命令行参数-自动装配ApplicationArguments

Spring Boot:自动装配具体类时“找不到类型的合格bean ...”

Spring Boot自动装配

spring boot自动装配原理@EnableAutoConfiguration