美文网首页
Spring Boot小记

Spring Boot小记

作者: eqgao | 来源:发表于2018-10-28 15:11 被阅读39次

    Spring Boot小记

    Spring启动容器对比

    ClassPathXmlApplicationContext(基于XML)

    ClassPathXmlApplicationContext.png

    AnnotationConfigApplicationContext(基于注解,非WEB版)

    AnnotationConfigApplicationContext.png

    AnnotationConfigEmbeddedWebApplicationContext(基于注解,WEB版)

    AnnotationConfigEmbeddedWebApplicationContext.png

    SpringBoot 启动流程

    认识ApplicationContextInitializer,SpringApplicationRunListener,Runner

    1、ApplicationContextInitializer,在Spring上下文被刷新之前进行初始化的操作。这个时候已经创建了ApplicationContext ,但是没有refresh(),ApplicationContextInitializer对ApplicationContext进行初始话操作。

    2、SpringApplicationRunListener,对ApplicationContext的运行各个时期的事件进行广播,时事件能够被ApplicationListener所监听到。

    startup2.jpg

    3、Runner,Spring上下文后置处理 Runners可以是两个接口的实现类: org.springframework.boot.ApplicationRunner org.springframework.boot.CommandLineRunner 其实没有什么不同之处,除了接口中的run方法接受的参数类型是不一样的以外。一个是封装好的ApplicationArguments类型,另一个是直接的String不定长数组类型。因此根据需要选择相应的接口实现即可。

    启动流程

    SpringBoot启动的时候,不论调用什么方法,都会构造一个SpringApplication的实例,然后调用这个实例的run方法,这样就表示启动SpringBoot。

    在run方法调用之前,也就是构造SpringApplication的时候会进行初始化的工作,初始化的时候会做以下几件事:

    1. 把参数sources设置到SpringApplication属性中,这个sources可以是任何类型的参数。本文的例子中这个sources就是MyApplication的class对象

    2. 判断是否是web程序,并设置到webEnvironment这个boolean属性中

    3. 找出所有的初始化器,默认有5个,设置到initializers属性中

    4. 找出所有的应用程序监听器,默认有9个,设置到listeners属性中

    5. 找出运行的主类(main class)

    SpringApplication构造完成之后调用run方法,启动SpringApplication,run方法执行的时候会做以下几件事:

    1. 构造一个StopWatch,观察SpringApplication的执行

    2. 找出所有的SpringApplicationRunListener并封装到SpringApplicationRunListeners中,用于监听run方法的执行。监听的过程中会封装成事件并广播出去让初始化过程中产生的应用程序监听器进行监听

    3. 构造Spring容器(ApplicationContext),并返回 3.1 创建Spring容器的判断是否是web环境,是的话构造AnnotationConfigEmbeddedWebApplicationContext,否则构造AnnotationConfigApplicationContext 3.2 初始化过程中产生的初始化器在这个时候开始工作 3.3 Spring容器的刷新(完成bean的解析、各种processor接口的执行、条件注解的解析等等)

    4. 从Spring容器中找出ApplicationRunner和CommandLineRunner接口的实现类并排序后依次执行

    SpringBoot 自动装载大致原理

    在@SpringBootApplication标签中引入了EnableAutoConfigurationImportSelector,其中调用了selectImports()方法,方法中调用org.springframework.boot.autoconfigure.EnableAutoConfigurationImportSelector#getCandidateConfigurations方法,使用SpringFactoryLoader把META-INF文件夹中的spring.factories文件中EnableAutoConfiguration为key的文件加载了。 加载的文件全部都是java config配置文件(有默认配置),利用@Conditional(Class<? extends Condition>[]) 标签,对相应的bean进行选择性的加载。

    SpringBoot 自动装载源码分析

    工厂加载类

    比较基本而且重要的一个类,运行加载了MATE-INF中的spring.factories 文件

    @Conditional原理

    @Conditional标签是全部Conditional相关标签的根源。 源码中Conditional标签使用的是ConditionEvaluator来解析,如下 org.springframework.context.annotation.AnnotatedBeanDefinitionReader#registerBean(java.lang.Class<?>, java.lang.String, java.lang.Class<? extends java.lang.annotation.Annotation>...) org.springframework.context.annotation.ConditionEvaluator#shouldSkip(org.springframework.core.type.AnnotatedTypeMetadata, org.springframework.context.annotation.ConfigurationCondition.ConfigurationPhase)

    加载java config原理

    在初始化AnnotationConfigApplicationContext的时候,对ConfigurationClassPostProcessor、AutowiredAnnotationBeanPostProcessor等类进行了注册。如下

    1. org.springframework.context.annotation.AnnotationConfigApplicationContext#AnnotationConfigApplicationContext()

    2. org.springframework.context.annotation.AnnotatedBeanDefinitionReader#AnnotatedBeanDefinitionReader(org.springframework.beans.factory.support.BeanDefinitionRegistry)

    3. org.springframework.context.annotation.AnnotatedBeanDefinitionReader#AnnotatedBeanDefinitionReader(org.springframework.beans.factory.support.BeanDefinitionRegistry, org.springframework.core.env.Environment)

    4. org.springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors(org.springframework.beans.factory.support.BeanDefinitionRegistry)

    5. org.springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors(org.springframework.beans.factory.support.BeanDefinitionRegistry, java.lang.Object)

    ConfigurationClassPostProcessor是一个BeanFactoryPostProcessor,所以会对BeanDefinitionRegistry或者BeanDefinition创建之后进行后置加工(refresh方法中,已经创建了BeanFactory,具体到运行到哪里看源码)。

    @import() 原理

    import解析原理根据的是ConfigurationClassPostProcessor,ConfigurationClassPostProcessor的加载过程参考上面 主要分析为啥@import标签是引入配置的但是却能够调用Selector的方法 org.springframework.context.annotation.ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry org.springframework.context.annotation.ConfigurationClassPostProcessor#processConfigBeanDefinitions org.springframework.context.annotation.ConfigurationClassParser#parse(java.util.Set<org.springframework.beans.factory.config.BeanDefinitionHolder>) org.springframework.context.annotation.ConfigurationClassParser#processDeferredImportSelectors 接着如下,调用了selectImports方法

        private void processDeferredImportSelectors() {
            List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
            this.deferredImportSelectors = null;
            Collections.sort(deferredImports, DEFERRED_IMPORT_COMPARATOR);
    
            for (DeferredImportSelectorHolder deferredImport : deferredImports) {
                ConfigurationClass configClass = deferredImport.getConfigurationClass();
                try {
                    String[] imports = deferredImport.getImportSelector().selectImports(configClass.getMetadata());
                    processImports(configClass, asSourceClass(configClass), asSourceClasses(imports), false);
                }
                catch (BeanDefinitionStoreException ex) {
                    throw ex;
                }
                catch (Exception ex) {
                    throw new BeanDefinitionStoreException("Failed to process import candidates for configuration class [" +
                            configClass.getMetadata().getClassName() + "]", ex);
                }
            }
        }
    

    相关文章

      网友评论

          本文标题:Spring Boot小记

          本文链接:https://www.haomeiwen.com/subject/zpnptqtx.html