• Springboot启动流程分析(一):IOC容器初始化


    目录

    AnnotationConfigServletWebServerApplicationContext类是什么

    IOC容器的组成

    1 BeanFactory

    2 ResourceLoader

    3 AliasRegistry

    4 小结

    AnnotationConfigServletWebServerApplicationContext是如何实例化的

    1 DefaultResourceLoader初始化

    2 AbstractApplicationContext初始化

    3 GenericApplicationContext初始化

    3.1 beanFactory 实例化

    4 GenericWebApplicationContext初始化

    5 ServletWebServerApplicationContext初始化

    6 AnnotationConfigServletWebServerApplicationContext初始化

    6.1 初始化AnnotatedBeanDefinitionReader

    6.2 初始化ClassPathBeanDefinitionScanner

    结尾


    我们对Springboot的启动程序想必都很熟悉:

    1. public class BookstoreApplication {
    2. public static void main(String[] args) {
    3. SpringApplication.run(BookstoreApplication.class, args);
    4. }
    5. }

    可以看到,核心便是SpringApplication类中的run方法:

    1. public ConfigurableApplicationContext run(String... args) {
    2. ......
    3. ConfigurableApplicationContext context = null;
    4. ......
    5. //1创建容器
    6. context = this.createApplicationContext();
    7. exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
    8. //2准备容器相关信息
    9. this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
    10. //3刷新容器,也就是通常我们说的bean的初始化
    11. this.refreshContext(context);
    12. //4完成初始化后处理
    13. this.afterRefresh(context, applicationArguments);
    14. ......
    15. }

    通过run方法的具体代码,我们可以看到,其核心流程便是四步:

    第一步,创建IOC容器

    第二步,准备IOC容器相关信息

    第三步,刷新IOC容器,也就是我们通常说的bean的初始化过程

    第四步,刷新IOC容器完成后处理

    当然从代码中,我们可以看到还有监听器,错误处理相关的内容,这些我们后续会讲到。

    我们今天主要讲第一步,如何创建IOC容器。

    其代码为:

    context = this.createApplicationContext();

    我们可以点击进去看看其具体是怎么做的:

    1. protected ConfigurableApplicationContext createApplicationContext() {
    2. Class contextClass = this.applicationContextClass;
    3. if (contextClass == null) {
    4. try {
    5. switch(this.webApplicationType) {
    6. case SERVLET:
    7. contextClass = Class.forName("org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext");
    8. break;
    9. case REACTIVE:
    10. contextClass = Class.forName("org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext");
    11. break;
    12. default:
    13. contextClass = Class.forName("org.springframework.context.annotation.AnnotationConfigApplicationContext");
    14. }
    15. } catch (ClassNotFoundException var3) {
    16. throw new IllegalStateException("Unable create a default ApplicationContext, please specify an ApplicationContextClass", var3);
    17. }
    18. }
    19. return (ConfigurableApplicationContext)BeanUtils.instantiateClass(contextClass);
    20. }

    可以看到,所谓的创建IOC容器就是通过全类名反射的方式,实例化了一个类:AnnotationConfigServletWebServerApplicationContext,后面的BeanUtils.instantiateClass(contextClass)其实就是通过Bean工具类对找到的类进行实例化。

    那么便来到了问题的核心,AnnotationConfigServletWebServerApplicationContext类是什么,有什么作用,为什么说它就是IOC容器?

    AnnotationConfigServletWebServerApplicationContext类是什么

    要知道这个类是什么,我们可以先看一张UML类图:

     上面这张图就是AnnotationConfigServletWebServerApplicationContext的集成和实现的接口、类的集合,由于太过庞杂,我们挑最重要的说,也就是我们用红框框起来的三个接口:

    BeanFactory
    ResourceLoader
    AliasRegistry

    我们一个个分析,这3个接口的作用。

    IOC容器的组成

    BeanFactory

    BeanFactory就是我们常说的bean工厂,这里说一句,我们这里说的BeanFactory不是实际的BeanFactory这个接口的具体作用,由于BeanFactory下面的实现类多而庞杂,无法一一列举,我们这里说的BeanFactory是虚指,表示BeanFactory极其实现接口和继承类的一系列功能。

    当然如果有BeanFactory系列中比较重要的,也会列举出来。

    先直接上代码,让我们对BeanFactory有一个较直观的理解:

    1. public interface BeanFactory {
    2. String FACTORY_BEAN_PREFIX = "&";
    3. Object getBean(String var1) throws BeansException;
    4. T getBean(String var1, Class var2) throws BeansException;
    5. ....
    6. ObjectProvider getBeanProvider(Class var1);
    7. ObjectProvider getBeanProvider(ResolvableType var1);
    8. .....
    9. String[] getAliases(String var1);
    10. }

    如果有用过Spring自带工具类的小伙伴想必对词不太陌生,我们经常会通过实现接口

    ApplicationContextAware

    的方式来获取IOC容器,之后再通过getBean的方法来获取容器中的指定对象。

    1. public interface ApplicationContextAware extends Aware {
    2. void setApplicationContext(ApplicationContext var1) throws BeansException;
    3. }

    其中的IOC容器便是ApplicationContext,通过上面的UML类图,我们可以看到ApplicationContext 其实是同时实现了BeanFactory和ResourceLoader这个两个接口的一个组合类。

    然后它的getBean方法其实就是直接来自于BeanFactory,用以从IOC容器中获取对象。

    还可以看到BeanFactory还有一些其他,诸如获取Bean别名、类型的、是否单例等方法,来获取Bean的一系列信息。

    我们常说BeanFactory是一个工厂,它能够通过获取getBean等方法Bean的一系列信息。那么既然是一个工厂,肯定不只是能获取Bean信息,它必然也具备创建Bean或者说实例化Bean的能力。那么BeanFactory是如何实例化Bean的呢?

    针对不同的业务需求,Bean的实例化方式其实有两种,单实例和多实例,实现方式呢?充分利用了面向对象的封装原则,默认的createBean方法是单例的,如果要创建多例的,在调用单例之前设置一下bean的定义信息为prototype即可。

    创建多实例Bean

    通过接口AutowireCapableBeanFactory对BeanFactory继承后扩展而来:

    1. public interface AutowireCapableBeanFactory extends BeanFactory {
    2. T createBean(Class var1) throws BeansException;
    3. void autowireBean(Object var1) throws BeansException;
    4. Object configureBean(Object var1, String var2) throws BeansException;
    5. Object createBean(Class var1, int var2, boolean var3) throws BeansException;
    6. Object autowire(Class var1, int var2, boolean var3) throws BeansException;

    创建单实例Bean

    一图胜千言,我们可以看一段继承逻辑,核心在抽象类AbstractBeanFactory上:

     可以看到AbstractBeanFactory同时实现了AliasRegistry和BeanFactory两个接口的功能,并在他们的基础上又增加了一些新功能,比如:

    1. public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
    2. @Nullable
    3. private BeanFactory parentBeanFactory;
    4. .......
    5. protected abstract boolean containsBeanDefinition(String var1);
    6. protected abstract BeanDefinition getBeanDefinition(String var1) throws BeansException;
    7. protected abstract Object createBean(String var1, RootBeanDefinition var2, @Nullable Object[] var3) throws BeanCreationException;
    8. }

    很明显了,通过名字就可以看出AbstractBeanFactory多做了些什么,它通过getBeanDefinition获取Bean生成Bean必要信息,最简单的就是例如全类名之类,然后再通过createBean来实例化Bean。

    前面我们说了,多实例和单实例的实例化过程其实是一样的,仅仅是多实例新值了一个属性,那么是如何实现的呢?

    这里得提到另一个重要的抽象类,AbstractAutowireCapableBeanFactory

     可以看到,它在继承AbstractBeanFactory的时候,实现了其单例的createBean方法,同时也实现了AutowireCapableBeanFactory用于多例创建的createBean方法。

    那么AbstractAutowireCapableBeanFactory是如何把两者集成起来的呢?直接看代码:

    1. public T createBean(Class beanClass) throws BeansException {
    2. RootBeanDefinition bd = new RootBeanDefinition(beanClass);
    3. bd.setScope("prototype");
    4. bd.allowCaching = ClassUtils.isCacheSafe(beanClass, this.getBeanClassLoader());
    5. return this.createBean(beanClass.getName(), bd, (Object[])null);
    6. }
    7. protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
    8. if (this.logger.isTraceEnabled()) {
    9. this.logger.trace("Creating instance of bean '" + beanName + "'");
    10. }
    11. ....

    可以看到,和我们说的一样,它通过实现public T createBean方法,设置多态属性后直接带调用protected Object createBean方法,实现了在复用代码的基础上,灵活的创建多/单实例的Bean。

    2 ResourceLoader

    要理解ResourceLoader,最简单的,直接看接口定义:

    1. public interface ResourceLoader {
    2. String CLASSPATH_URL_PREFIX = "classpath:";
    3. Resource getResource(String var1);
    4. @Nullable
    5. ClassLoader getClassLoader();
    6. }

    可以看到,它的三个属性,基本就代表了这个类的作用:

    1 String CLASSPATH_URL_PREFIX = "classpath:"是什么

    classpath指的是java代码经过编译后,生成的target文件夹下的classes下的路径,具体如下

    2  Resource getResource(String var1)是什么

    Resource就是在基于classpath路径的基础上,classes文件夹下的真是文件路径,例如我们要取application.yml的路径,在基于classpath的基础上直接getResource("application.yml")即可。

    3 ClassLoader getClassLoader()是什么

    ClassLoader 就是类加载器,根据JVM的知识,我们知道,即使是对于同一个全限定类名完全相同的类,如果采用了不同的类加载器,那它就可以认为是两个完全不相等的类。

    所以呢,此处获取类加载器的作用和上文获取classpath类似,获取一个统一的加载器,为后面的加载类做准备。

    3 AliasRegistry

    要理解AliasRegistry要和它的继承接口BeanDefinitionRegistry一起看,其实从接口名就可以看出它是做什么的,Bean定义信息注册:

    1. public interface AliasRegistry {
    2. void registerAlias(String var1, String var2);
    3. void removeAlias(String var1);
    4. ......
    5. }
    6. public interface BeanDefinitionRegistry extends AliasRegistry {
    7. void registerBeanDefinition(String var1, BeanDefinition var2) throws BeanDefinitionStoreException;
    8. void removeBeanDefinition(String var1) throws NoSuchBeanDefinitionException;
    9. BeanDefinition getBeanDefinition(String var1) throws NoSuchBeanDefinitionException;
    10. boolean containsBeanDefinition(String var1);
    11. String[] getBeanDefinitionNames();
    12. .........
    13. }

    依旧是顾名思义,从他们的接口方法就可以看出来,无非就是注册Bean的定义信息,获取bean的定义信息之类。

    4 小结

    通过对上面三个类型接口的分析,我们可以大概了解到IOC容器的组成,能够看出,整个IOC其实是围绕BeanFactory来做文章的,就像工厂一样:来料加工,利用机器生产产品。IOC也是通过Bean的定义信息,利用类加载器,来生产Bean的实例。整个大略的流程基本类似,当然我们这里还没有开始进行实例化,仅仅是对IOC的整体进行概览。

    AnnotationConfigServletWebServerApplicationContext是如何实例化的

    通过上文的分析,我们了解了IOC的基本组成部分,同时可以看出整个IOC容器的初始化,其实就是方法createApplicationContext()调用AnnotationConfigServletWebServerApplicationContext这个类的实例化过程。

    那么AnnotationConfigServletWebServerApplicationContext是如何实例化的呢?

    在此之前,我们要回顾一下最开始的那张UML类图的部分内容,在此我们简单文字说明一下,整张UML类图,基本就是在继承接口信息,但是多数的接口信息仅仅是对接口功能进行了定义,其实在实例化的时候并无多少意义,除非实例化的过程中又去调用了接口的实现方法。

    对于UML类图中的接口继承来说,更多的是继承其定义,以便于后面引用。

    真正对初始化来说有意义的,其实是AnnotationConfigServletWebServerApplicationContext这个类的父类,及其父类的父类。

    我们知道,对于Java来说,一个类的实例化,如果它有继承关系的话,它会一直向上去寻找到它的初始父类,然后初始化,然后转到下一层再初始化,一直到我们实际初始化的类:

      可以看到,是和前面的UML类图的继承类是一脉相承的,其从上往下的继承顺序为:

    DefaultResourceLoader
    AbstractApplicationContext
    GenericApplicationContext
    GenericWebApplicationContext
    ServletWebServerApplicationContext
    AnnotationConfigServletWebServerApplicationContext

    其实严格意义上来说AbstractApplicationContext作为顶层的父类之一,还是一个抽象类,是不能够实例化的,这里更多的是一种父类信息的初始化。

    换一种方式来说,其实可以认为AnnotationConfigServletWebServerApplicationContext这个类是在取得了它所有继承类的所有信息之后进行的初始化,这样就能够获取到IOC容器初始化的所有必要信息了。

    而继承的方式,更多的是为了减少代码的复用,虽然这样对初始化这件事的理解会稍微麻烦点,但是总归利大于弊。

    到这里,我们认为AnnotationConfigServletWebServerApplicationContext的实例化,是对上面六个从上往下依次继承类,所有信息的一次实例化。

    那么其具体做了什么呢?我们按顺序,一个个来看,它们分别都做了什么。

    1 DefaultResourceLoader初始化

    1. public DefaultResourceLoader() {
    2. this.classLoader = ClassUtils.getDefaultClassLoader();
    3. }

    可以看到,第一步就是获取了系统默认的类加载器。

    2 AbstractApplicationContext初始化

    1. public AbstractApplicationContext() {
    2. this.logger = LogFactory.getLog(this.getClass());
    3. this.id = ObjectUtils.identityToString(this);
    4. this.displayName = ObjectUtils.identityToString(this);
    5. this.beanFactoryPostProcessors = new ArrayList();
    6. this.active = new AtomicBoolean();
    7. this.closed = new AtomicBoolean();
    8. this.startupShutdownMonitor = new Object();
    9. this.applicationListeners = new LinkedHashSet();
    10. this.resourcePatternResolver = this.getResourcePatternResolver();
    11. }

    第二步,可以看到基本都是一些信息的初始化。

    3 GenericApplicationContext初始化

    1. public GenericApplicationContext() {
    2. this.customClassLoader = false;
    3. this.refreshed = new AtomicBoolean();
    4. this.beanFactory = new DefaultListableBeanFactory();
    5. }

    第三步,可以看到也是一些信息初始化,还有最重要的一点,初始化了beanFactory,这个就是用于后续创建bean的。

    这里可以看到Spring框架设计很巧妙的一点,其实严格意义上来说,AnnotationConfigServletWebServerApplicationContext也是一个beanFactory,因为也实现了BeanFactory接口,那为什么要用组合的方式,来实例化一个beanFactory作为自己的属性呢?

    3.1 beanFactory 实例化

    为什么要选DefaultListableBeanFactory作为beanFactory呢?依旧是通过UML类图来看:

     可以看到DefaultListableBeanFactory在实现和继承AliasRegistry接口信息,能够获取bean定义信息的基础上,也实现了BeanFactory下面的一系列接口。使他能够通过bean定义信息来创建bean。

    那么DefaultListableBeanFactory又是如何实力话的呢?不能单看它本身,得从它的顶层父类开始,一层层看,才知道它做了什么,通过上图的蓝色继承箭头,我们可以找到它的顶层父类SimpleAliasRegistry开始,通过它们的空参构造器,一层层往下看:

    1. public SimpleAliasRegistry() {
    2. }
    3. public DefaultSingletonBeanRegistry() {
    4. }
    5. public FactoryBeanRegistrySupport() {
    6. }
    7. public AbstractBeanFactory() {
    8. }
    9. public AbstractAutowireCapableBeanFactory() {
    10. this.instantiationStrategy = new CglibSubclassingInstantiationStrategy();
    11. this.parameterNameDiscoverer = new DefaultParameterNameDiscoverer();
    12. this.allowCircularReferences = true;
    13. this.allowRawInjectionDespiteWrapping = false;
    14. this.ignoredDependencyTypes = new HashSet();
    15. this.ignoredDependencyInterfaces = new HashSet();
    16. this.currentlyCreatedBean = new NamedThreadLocal("Currently created bean");
    17. this.factoryBeanInstanceCache = new ConcurrentHashMap();
    18. this.factoryMethodCandidateCache = new ConcurrentHashMap();
    19. this.filteredPropertyDescriptorsCache = new ConcurrentHashMap();
    20. this.ignoreDependencyInterface(BeanNameAware.class);
    21. this.ignoreDependencyInterface(BeanFactoryAware.class);
    22. this.ignoreDependencyInterface(BeanClassLoaderAware.class);
    23. }
    24. public DefaultListableBeanFactory() {
    25. }

    可以看到,除了AbstractAutowireCapableBeanFactory初始化了一系列信息,包括初始化策略,忽略依赖类型等等,再加上一个实例化当前对象。这就是beanFactory的初始化全过程。

    基本就是仅仅设置了一系列初始化参数。

    4 GenericWebApplicationContext初始化

    1. public GenericWebApplicationContext() {
    2. }

    略过。

    5 ServletWebServerApplicationContext初始化

    1. public ServletWebServerApplicationContext() {
    2. }

    略过。

    6 AnnotationConfigServletWebServerApplicationContext初始化

    1. public AnnotationConfigServletWebServerApplicationContext() {
    2. this.annotatedClasses = new LinkedHashSet();
    3. this.reader = new AnnotatedBeanDefinitionReader(this);
    4. this.scanner = new ClassPathBeanDefinitionScanner(this);
    5. }

    可以看到,初始化了beanFactory以后,最重要的工作就是初始化reader和scanner了。

    在进入下一步之前,我们先看看此时的this包含了哪些内容,首先就是代表自身的实例了,根据其继承关系,它既可以是一个BeanFactory实例,也可以是一个AliasRegistry实例。

    其在初始化的过程中,还通过组合的方式,添加了一些附加属性,例如ClassLoader、BeanFactory。再说直白点就是可以通过get的方式来获取ClassLoader或者DefaultListableBeanFactory生成的BeanFactory实例。

    6.1 初始化AnnotatedBeanDefinitionReader

    1. public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
    2. this(registry, getOrCreateEnvironment(registry));
    3. }

    可以看到,在reader的实例化过程中,AnnotationConfigServletWebServerApplicationContext把自身实例化后的bean当作了BeanDefinitionRegistry(AliasRegistry的直接继承接口),作为参数传递给reader,供reader实例化。

    这样肯定也没问题,毕竟上文说了AnnotationConfigServletWebServerApplicationContext既可以是BeanFactory,也可以被当作AliasRegistry。

    获取环境信息Environment

    在进入reader的有参构造器后,我们发现还执行了一个getOrCreateEnvironment(registry)方法,依然是把AnnotationConfigServletWebServerApplicationContext当作BeanDefinitionRegistry来用:

    1. private static Environment getOrCreateEnvironment(BeanDefinitionRegistry registry) {
    2. Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
    3. return (Environment)(registry instanceof EnvironmentCapable ? ((EnvironmentCapable)registry).getEnvironment() : new StandardEnvironment());
    4. }

    简单来说就是获取Environment环境信息,为什么可以通过BeanDefinitionRegistry获取Environment呢?

    依旧是在最开始的UML类图中,只不过没有标注出来:

    可以看到是由于ApplicationContext继承了EnvironmentCapable接口:

    1. public interface EnvironmentCapable {
    2. Environment getEnvironment();
    3. }

     而Environment 其实我们应该也很熟悉:

    1. public interface Environment extends PropertyResolver {
    2. String[] getActiveProfiles();
    3. String[] getDefaultProfiles();
    4. ......
    5. }

    就是获取当前的可用的ActiveProfiles的,这个在我们的yml配置很常见。

    继续实例化AnnotatedBeanDefinitionReader

    1. public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
    2. this.beanNameGenerator = AnnotationBeanNameGenerator.INSTANCE;
    3. this.scopeMetadataResolver = new AnnotationScopeMetadataResolver();
    4. Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
    5. Assert.notNull(environment, "Environment must not be null");
    6. this.registry = registry;
    7. this.conditionEvaluator = new ConditionEvaluator(registry, environment, (ResourceLoader)null);
    8. AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
    9. }

    一个个说:

    beanNameGenerator,用来获取实例化的beanName。

    scopeMetadataResolver,用来获取注解里面的属性,类似于value之类。

    conditionEvaluator,用来评估当前的beanFactory处于什么环境:

    1. public ConditionContextImpl(@Nullable BeanDefinitionRegistry registry, @Nullable Environment environment, @Nullable ResourceLoader resourceLoader) {
    2. this.registry = registry;
    3. this.beanFactory = this.deduceBeanFactory(registry);
    4. this.environment = environment != null ? environment : this.deduceEnvironment(registry);
    5. this.resourceLoader = resourceLoader != null ? resourceLoader : this.deduceResourceLoader(registry);
    6. this.classLoader = this.deduceClassLoader(resourceLoader, this.beanFactory);
    7. }

    主要也是做的一些准备工作,其中需要注意的是

    this.beanFactory = this.deduceBeanFactory(registry);

     这个获取beanFactory的方法:

    1. private ConfigurableListableBeanFactory deduceBeanFactory(@Nullable BeanDefinitionRegistry source) {
    2. if (source instanceof ConfigurableListableBeanFactory) {
    3. return (ConfigurableListableBeanFactory)source;
    4. } else {
    5. return source instanceof ConfigurableApplicationContext ? ((ConfigurableApplicationContext)source).getBeanFactory() : null;
    6. }
    7. }

    也就是说你这个被当作registry的AnnotationConfigServletWebServerApplicationContext到底是属于ConfigurableListableBeanFactory还是ConfigurableApplicationContext 。

    通过前面DefaultListableBeanFactory类生成beanFactory的过程,我们可以看出,其实DefaultListableBeanFactory是实现了ConfigurableListableBeanFactory接口,而AnnotationConfigServletWebServerApplicationContext则实现了ConfigurableApplicationContext接口。

    而由于DefaultListableBeanFactory类生成beanFactory作为一个属性赋予了当前参数名为register的AnnotationConfigServletWebServerApplicationContext,所以此时返回的beanFactory就是DefaultListableBeanFactory。

    简单来说就是此时的beanFactory就是register里面的属性之一,要用就直接get。

    那么现在reader的实例化还剩最后一步。

    AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);

     

    1. public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
    2. registerAnnotationConfigProcessors(registry, (Object)null);
    3. }
    4. public static Set registerAnnotationConfigProcessors(BeanDefinitionRegistry registry, @Nullable Object source) {
    5. //第一步,获取beanFactory
    6. DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
    7. //第二步,设置beanFactory的属性
    8. if (beanFactory != null) {
    9. if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
    10. beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
    11. }
    12. if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
    13. beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
    14. }
    15. }
    16. //第三步,在beanFactory中,注册
    17. Set beanDefs = new LinkedHashSet(8);
    18. RootBeanDefinition def;
    19. if (!registry.containsBeanDefinition("org.springframework.context.annotation.internalConfigurationAnnotationProcessor")) {
    20. def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
    21. def.setSource(source);
    22. beanDefs.add(registerPostProcessor(registry, def, "org.springframework.context.annotation.internalConfigurationAnnotationProcessor"));
    23. }
    24. if (!registry.containsBeanDefinition("org.springframework.context.annotation.internalAutowiredAnnotationProcessor")) {
    25. def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
    26. def.setSource(source);
    27. beanDefs.add(registerPostProcessor(registry, def, "org.springframework.context.annotation.internalAutowiredAnnotationProcessor"));
    28. }
    29. if (jsr250Present && !registry.containsBeanDefinition("org.springframework.context.annotation.internalCommonAnnotationProcessor")) {
    30. def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
    31. def.setSource(source);
    32. beanDefs.add(registerPostProcessor(registry, def, "org.springframework.context.annotation.internalCommonAnnotationProcessor"));
    33. }
    34. if (jpaPresent && !registry.containsBeanDefinition("org.springframework.context.annotation.internalPersistenceAnnotationProcessor")) {
    35. def = new RootBeanDefinition();
    36. try {
    37. def.setBeanClass(ClassUtils.forName("org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor", AnnotationConfigUtils.class.getClassLoader()));
    38. } catch (ClassNotFoundException var6) {
    39. throw new IllegalStateException("Cannot load optional framework class: org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor", var6);
    40. }
    41. def.setSource(source);
    42. beanDefs.add(registerPostProcessor(registry, def, "org.springframework.context.annotation.internalPersistenceAnnotationProcessor"));
    43. }
    44. if (!registry.containsBeanDefinition("org.springframework.context.event.internalEventListenerProcessor")) {
    45. def = new RootBeanDefinition(EventListenerMethodProcessor.class);
    46. def.setSource(source);
    47. beanDefs.add(registerPostProcessor(registry, def, "org.springframework.context.event.internalEventListenerProcessor"));
    48. }
    49. if (!registry.containsBeanDefinition("org.springframework.context.event.internalEventListenerFactory")) {
    50. def = new RootBeanDefinition(DefaultEventListenerFactory.class);
    51. def.setSource(source);
    52. beanDefs.add(registerPostProcessor(registry, def, "org.springframework.context.event.internalEventListenerFactory"));
    53. }
    54. return beanDefs;
    55. }

    对照代码,一步步分析:

     第一步,获取beanFactory:

    DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
    1. private static DefaultListableBeanFactory unwrapDefaultListableBeanFactory(BeanDefinitionRegistry registry) {
    2. if (registry instanceof DefaultListableBeanFactory) {
    3. return (DefaultListableBeanFactory)registry;
    4. } else {
    5. return registry instanceof GenericApplicationContext ? ((GenericApplicationContext)registry).getDefaultListableBeanFactory() : null;
    6. }
    7. }

    可以看到,基本和上面判断获取beanFactory的方式意义,由于beanFactory是以组合的方式放在register里面,所以通过getDefaultListableBeanFactory()返回beanFactory。

    第二步,设置beanFactory的属性。

    1. if (beanFactory != null) {
    2. if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
    3. beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
    4. }
    5. if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
    6. beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
    7. }
    8. }

    由于当前的beanFactory是DefaultListableBeanFactory实例化而来,所以这2属性都得去DefaultListableBeanFactory里面看,到底是什么,根据其初始化值我们可以判断其instanceof:

    1. public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
    2. ......
    3. @Nullable
    4. private Comparator dependencyComparator;
    5. private AutowireCandidateResolver autowireCandidateResolver = new SimpleAutowireCandidateResolver();
    6. public DefaultListableBeanFactory() {
    7. }
    8. ......
    9. public AutowireCandidateResolver getAutowireCandidateResolver() {
    10. return this.autowireCandidateResolver;
    11. }
    12. @Nullable
    13. public Comparator getDependencyComparator() {
    14. return this.dependencyComparator;
    15. }
    16. 可以看到,由于DefaultListableBeanFactory是使用空参构造器实例化的,其dependencyComparator为null,而autowireCandidateResolver也是一个类型为SimpleAutowireCandidateResolver的空参实例。

      可以看出,这里是给beanFactory设置两个属性,分别是依赖的优先级属性和注解的解析器。

      第三步,注册bean信息

      第三步代码看上去很复杂,其实主要就做了一件事:

      registry.registerBeanDefinition(beanName, definition);

      把bean的信息,以map的形式维护到IOC容器中。其主要实现形式便是put:

      this.beanDefinitionMap.put(beanName, beanDefinition);
      1. public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
      2. private final Map beanDefinitionMap = new ConcurrentHashMap(256);

      beanDefinitionMap也是当前beanFactory实例化时,初始化的一个map属性。

      这里再额外说一下,那么当前状态下,放入的bean定义信息又是些什么呢?通过上面的源码我们可以看到,主要是bean工程的后置处理器接口BeanFactoryPostProcessor、bean的初始化时后置处理器接口BeanPostProcessor、监听器工厂EventListenerFactory接口的一些实现类的bean定义信息,后面我们用到了会详细讲解。这里先对这几个接口有一个直观的认识:

      1. @FunctionalInterface
      2. public interface BeanFactoryPostProcessor {
      3. void postProcessBeanFactory(ConfigurableListableBeanFactory var1) throws BeansException;
      4. }
      5. public interface BeanPostProcessor {
      6. @Nullable
      7. default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
      8. return bean;
      9. }
      10. @Nullable
      11. default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
      12. return bean;
      13. }
      14. }
      15. public interface EventListenerFactory {
      16. boolean supportsMethod(Method var1);
      17. ApplicationListener createApplicationListener(String var1, Class var2, Method var3);
      18. }

      小结

      通过上面的代码分析可以看到,其实reader实例化的过程,主要就是为了把一些指定的bean定义信息放入到AnnotationConfigServletWebServerApplicationContext的beanDefinitionMap中。

      6.2 初始化ClassPathBeanDefinitionScanner

      上面我们说到了,AnnotationConfigServletWebServerApplicationContext中的初始化主要就是reader和scanner的对象构造,上面讲完了reader,下面我们开始说scanner。

      要想知道scanner是做什么的,首先我们要知到ClassPathBeanDefinitionScanner是个什么?

       EnvironmentCapable前面我们已经看过了,就是获取Environment信息的一个接口,那么Aware又是什么呢?

      1. public interface Aware {
      2. }

      可以看到,其是一个空接口,一般通过继承它的方式来给指定类做自定义增强。

      1. public interface ResourceLoaderAware extends Aware {
      2. void setResourceLoader(ResourceLoader var1);
      3. }

      通过EnvironmentCapable和ResourceLoaderAware这2个接口,我们可以看出ClassPathBeanDefinitionScanner这个类,应该是主要是关于类加载器和系统环境有关的一些信息。

      通过其初始化代码,我们也能看到:

      1. public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry) {
      2. this(registry, true);
      3. }
      4. public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters) {
      5. this(registry, useDefaultFilters, getOrCreateEnvironment(registry));
      6. }
      7. public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters, Environment environment) {
      8. this(registry, useDefaultFilters, environment, registry instanceof ResourceLoader ? (ResourceLoader)registry : null);
      9. }
      10. public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters, Environment environment, @Nullable ResourceLoader resourceLoader) {
      11. this.beanDefinitionDefaults = new BeanDefinitionDefaults();
      12. this.beanNameGenerator = AnnotationBeanNameGenerator.INSTANCE;
      13. this.scopeMetadataResolver = new AnnotationScopeMetadataResolver();
      14. this.includeAnnotationConfig = true;
      15. Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
      16. this.registry = registry;
      17. if (useDefaultFilters) {
      18. this.registerDefaultFilters();
      19. }
      20. this.setEnvironment(environment);
      21. this.setResourceLoader(resourceLoader);
      22. }

      可以看到,也是把register中的信息拆分后,对ClassPathBeanDefinitionScanner进行初始化,再给其属性赋值,主要是把环境变量和类加载器一起传递过去。

      结尾

      可以看到,在Springboot的启动过程中,所谓的IOC容器便是由类AnnotationConfigServletWebServerApplicationContext初始化的一个实例,其中包含了bean工厂、类加载器、bean定义信息和环境变量等主要信息。

      通过AnnotationConfigServletWebServerApplicationContext的初始化,IOC容器初始化了一些属性,设置了一些特定的bean定义信息。其主要的作用,还是为后续的IOC容器创建Bean做准备。

    17. 相关阅读:
      企业数据集成难?Qlik 与微软助你事半功倍
      浅谈矩阵 学习笔记
      1.创建项目(wpf视觉项目)
      基于微信小程序的校招应聘系统设计与实现(源码+lw+部署文档+讲解等)
      WebDAV之π-Disk派盘 + Keepass2Android
      Ubuntu系统下安装rpm安装包的方法
      wsl2环境的搭建
      VoxWeekly|The Sandbox 生态周报|20230904
      第三十五章 使用 CSP 进行基于标签的开发 - 使用服务器端方法的提示
      高考十年了,聊聊挣钱这件事
    18. 原文地址:https://blog.csdn.net/bigbearxyz/article/details/126419641