zoukankan      html  css  js  c++  java
  • spring boot源码阅读

    先看官网。。。。。

    https://spring.io/projects/spring-boot

    总览

    通过Spring Boot,可以轻松地创建独立的,基于生产级别和基于Spring的应用程序,并且可以“运行”它们。

    我们对Spring平台和第三方库坚持自己的的观点,因此您可以以最小的麻烦开始使用。大多数Spring Boot应用程序只需要需要非常少的的Spring配置。

    特征

    • 创建独立的Spring应用程序

    • 直接嵌入Tomcat,Jetty或Undertow(无需部署WAR文件)

    • 提供默认的“入门”依赖项,以简化构建配置

    • 尽可能自动配置Spring和第三方库

    • 提供可用于生产的功能,例如指标,运行状况检查和外部化配置

    • 完全没有代码生成,也不需要XML配置

    入门

     


    好了,开始看源码吧
     
     
    1、先找到入口(项目创建自己搞,这都不会看毛源码):
      主类->SpringApplication.run->this.run->new SpringApplication().run()
    2、就从SpringApplication的run(String... args)方法开始看

      2.1、先看注解:运行Spring的应用程序,正在创建和刷新一个新的ApplicationContext(Spring IOC容器),大体的意思就是要创建并刷新一个IOC容器,也就是说Spring boot基于IOC容器的扩展,不同的地方应该大部分在于扩展的部分

       /**
         * Run the Spring application, creating and refreshing a new
         * {@link ApplicationContext}.
         * @param args the application arguments (usually passed from a Java main method)
         * @return a running {@link ApplicationContext}
         */

      2.2、外围的主要方法就是这些了,直接看注释

      /**
         * Run the Spring application, creating and refreshing a new
         * {@link ApplicationContext}.
         * @param args the application arguments (usually passed from a Java main method)
         * @return a running {@link ApplicationContext}
         */
        public ConfigurableApplicationContext run(String... args) {
            // 1、计时器 启动
            StopWatch stopWatch = new StopWatch();
            stopWatch.start();
    
            // 2、设置一个可配置的应用上下文(IOC容器)变量,赋默认值
            ConfigurableApplicationContext context = null;
            // 3、初始化一个异常报告器列表
            Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
            // 4、配置一个java.awt.headless系统属性,好像是用来配置像linux服务器这种没有显示设备的机子用的
            configureHeadlessProperty();
            // 5、获取Spring应用程序运行监听器,这些监听器看起来主要应用在spring boot的run方法之中,没有和spring refresh方法里面的一起
            SpringApplicationRunListeners listeners = getRunListeners(args);
            // 6、看上去像是启动监听器,实际上是传播starting事件给监听器,listeners可以理解为组合模式吧,这个容器包裹了一堆监听器,对外的方法基本上都是遍历调用这些监听器的具体方法
            // (一)第一次监听器传播 应用启动事件
            listeners.starting();
            try {
                // 7、将命令行参数包裹到容器中
                ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
                // 8、初始化一个可配置的环境(根据应用类型),这边主要是准备工作(listeners将在这里第二次调用,(二)第二次监听器传播,环境准备就绪事件)
                ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
                // 9、从环境变量中读取是否忽略beanInfo信息的配置,并设置到系统参数
                configureIgnoreBeanInfo(environment);
                // 10、打印banner,就是用命令行打印出spring boot的那个logo的一些信息
                Banner printedBanner = printBanner(environment);
                // 11、给应用上下文设置一个实际的对象(根据应用类型)
                context = createApplicationContext();
                // 12、从spring.factory中读取并初始化异常报告器
                exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
                        new Class[] { ConfigurableApplicationContext.class }, context);
                // 13、context的准备工作,包括一些属性设置,初始化器的调用,(三)第三次监听器传播,context读取就绪事件...
                prepareContext(context, environment, listeners, applicationArguments, printedBanner);
                // 14、刷新容器,基本上就又到了Spring IOC的核心方法,refresh里面了
                refreshContext(context);
                // 15、扩展用的,在刷新context之后调用
                afterRefresh(context, applicationArguments);
                // 1、计时器 结束
                stopWatch.stop();
                if (this.logStartupInfo) {
                    new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
                }
                // 16、(四)第四次监听器传播,应用启动事件
                listeners.started(context);
                // 17、执行一些注册好的命令对象ApplicationRunner或CommandLineRunner的bean list
                callRunners(context, applicationArguments);
            }
            catch (Throwable ex) {
                handleRunFailure(context, ex, exceptionReporters, listeners);
                throw new IllegalStateException(ex);
            }
    
            try {
                // 18、(五)第五次监听器传播,应用运行中事件
                listeners.running(context);
            }
            catch (Throwable ex) {
                handleRunFailure(context, ex, exceptionReporters, null);
                throw new IllegalStateException(ex);
            }
            return context;
        }

      2.3、里面各自有很多细节,如果一个一个讲没太大意思,还是要自己看;主要还是看看Spring boot的自动配置、自动装配的部分

        2.3.1、重点外围方法:prepareContext这里面主要是有两个事情,一个是注册了我们的主类到DefaultListableBeanFactory到BeanDefinition里面(后面会用来作为根节点解析配置文件)【入口是load方法】,另一个是init了添加了两个beanFactoryPostProcess【入口是:applyInitializers】

        

       2.3.2、refreshContext这个方法看名字就知道最终会调用到Spring的refresh方法,spring的就不再细看了,直接看spring预留用来执行扩展方法的invokeBeanFactoryPostProcessors方法

        最终跟到PostProcessorRegistrationDelegate这个类中的invokeBeanFactoryPostProcessors方法

      

    public static void invokeBeanFactoryPostProcessors(
                ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
    
            // Invoke BeanDefinitionRegistryPostProcessors first, if any.
            Set<String> processedBeans = new HashSet<>();
            
            if (beanFactory instanceof BeanDefinitionRegistry) {
                BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
                List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
                List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
                // 1、分组
                for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
                    if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
                        BeanDefinitionRegistryPostProcessor registryProcessor =
                                (BeanDefinitionRegistryPostProcessor) postProcessor;
                        registryProcessor.postProcessBeanDefinitionRegistry(registry);
                        registryProcessors.add(registryProcessor);
                    }
                    else {
                        regularPostProcessors.add(postProcessor);
                    }
                }
    
                // Do not initialize FactoryBeans here: We need to leave all regular beans
                // uninitialized to let the bean factory post-processors apply to them!
                // Separate between BeanDefinitionRegistryPostProcessors that implement
                // PriorityOrdered, Ordered, and the rest.
                List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
    
                // 2、执行优先级最高的BeanDefinitionRegistryPostProcessors处理器 开始
                // 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);
                // 我只引入了spring-boot-web,这里仅仅获取到了ConfigurationClassPostProcessor,
                invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
                currentRegistryProcessors.clear();
                // 2、执行优先级最高的BeanDefinitionRegistryPostProcessors处理器  结束
    
                // 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);
                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);
                    currentRegistryProcessors.clear();
                }
    
                // Now, invoke the postProcessBeanFactory callback of all processors handled so far.
                invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
                invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
            }
    
            else {
                // Invoke factory processors registered with the context instance.
                invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
            }
    
            // Do not initialize FactoryBeans here: We need to leave all regular beans
            // uninitialized to let the bean factory post-processors apply to them!
            String[] postProcessorNames =
                    beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
    
            // Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
            // Ordered, and the rest.
            List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
            List<String> orderedPostProcessorNames = new ArrayList<>();
            List<String> nonOrderedPostProcessorNames = new ArrayList<>();
            for (String ppName : postProcessorNames) {
                if (processedBeans.contains(ppName)) {
                    // skip - already processed in first phase above
                }
                else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
                    priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
                }
                else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
                    orderedPostProcessorNames.add(ppName);
                }
                else {
                    nonOrderedPostProcessorNames.add(ppName);
                }
            }
    
            // First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
            sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
            invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
    
            // Next, invoke the BeanFactoryPostProcessors that implement Ordered.
            List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
            for (String postProcessorName : orderedPostProcessorNames) {
                orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
            }
            sortPostProcessors(orderedPostProcessors, beanFactory);
            invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
    
            // Finally, invoke all other BeanFactoryPostProcessors.
            List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
            for (String postProcessorName : nonOrderedPostProcessorNames) {
                nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
            }
            invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
    
            // Clear cached merged bean definitions since the post-processors might have
            // modified the original metadata, e.g. replacing placeholders in values...
            beanFactory.clearMetadataCache();
        }
       ConfigurationClassPostProcessor这个对象的postProcessBeanDefinitionRegistry方法会先被执行,里面方法还比较杂
       后面会运行到processConfigBeanDefinitions这个方法里面
      

    可以看到最终只过滤到了这个主类

    再看到parse这行代码

     

    接下来这个方法实在代码有点多,反正上面这个方法入口进去之后,大致就是不断自下而上(就是子配置加载完,再加载父类的配置,

    直到没有父类)地解析配置(主要是注解) 

    大概看一下也能知道,@CompentScan和@Import,都是自动配置装配相关的,这里会尽可能地将配置都解析出来

    (不过应该还不包含一些要动态引入的,其次是这里还不是最终处理的逻辑,主要还是解析) 解析完了之后我们回

    到下面这个方法

     

     接下来这个就是最终实际执行的方法

     

    注意看下上面这个group实际是AutoConfigurationImportSelector

     上面这个方法,实际最终从spring.factories文件里面读取出来n多个(目前我的项目里面是120多个),自动化配置需要加载的配置文件

    不过最终还会过滤掉一些重复或者不需要的配置,这边过滤完之后是剩下20几条 

    最后又会回到解析配置的那步(就是自下而上一直解析配置的那里)

    反正。。。。最终解析完之后,又到了spring的refresh方法里面去实例化bean,大致是这样吧。

    从上面的过程来看,其实也可以推导出,如果我们要自己设置一个starter,那么基本上只要自己配置一个class,并且将其写入spring.factories里面的,基本上就ok了

    org.springframework.boot.autoconfigure.EnableAutoConfiguration=

    ps:由于理解有限,可能有错误的点自己也不清楚,读者自己要自己留意下,哈哈(也许有坑),毕竟看源码容易把人看晕掉

    简单总结下:

    1. SpringApplication的一些方法执行
      1. prepareContext -> 添加主类到要扫描的配置文件列表中,注册BeanFactoryPostProcess
      2. refreshContext -> AbstractApplicationContext refresh()
    2. AbstractApplicationContext的refresh方法
    3. invokeBeanFactoryPostProcessors方法
    4. 调用优先级最高的BeanFactoryPostProcess(ConfigurationClassPostProcessor)处理BeanDefinition的注册
    5. 调用到ConfigurationClassParser解析,
      1. 初步解析(初步解析是通过主类,将所有配置加载寄哪里)
      2. 继续调用importSelector的解析(相当于解析到了@Import,然后将AutoConfigurationImportSelector先放到一个列表中,在这一步继续解析)
      3. 最终应该又得调用初步解析中调用到的方法,把所有的配置都加载出来
    6. AbstractApplicationContext的finishBeanFactoryInitialization方法,把所有配置和普通bean都实例化
    7. 最终程序启动,写的太细的话,绝对要晕,这边就写个大概

    反正思路吧。首先我们先读过spring 源码,就大概知道留了个beanFactoryPostProcess的口给扩展的人了

    其次,通过使用,我们知道关键的注解是EnableAutoConfiguration(当然一般在这里我们还不一定知道和@Import(AutoConfigurationImportSelector.class) 的关系)

    所以只能跟着源码运行最终发现初步解析之后,还会继续处理ImportSelector的解析,我们才发现上面这个关系

    最终理解了,就是先加载主类配置,通过主类配置发现EnableAutoConfiguration,再通过EnableAutoConfiguration import AutoConfigurationImportSelector

    AutoConfigurationImportSelector解析了spring.factories里面的EnableAutoConfiguration下的配置列表

    千万千万不要被那个重复解析的代码给绕晕了,其次是不要在这里找实例化代码,如果我理解没错的话,实例化最终是spring 容器的事情,还有就是不要用spring cloud的版本来看,我差点没被搞死。。。第一次看还是老实点,看纯净版的

  • 相关阅读:
    如何配置docker的镜像源?
    ubuntu18.04下dns如何设置?
    ubuntu 18.04上执行buildman安装了交叉工具链之后编译报错"aarch64-linux/7.3.0/cc1: error while loading shared libraries: libmpfr.so.4: cannot open shared object file: No such file or directory"如何处理?
    iptables执行时报错"iptables : Couldn't load target `standard':No such file or directory"如何处理?
    Resharper 2019.1.1 破解
    Mac 使用笔记
    SpringBoot使用Nacos配置中心
    Springcloud gateway获取post请求内容
    scp命令详解
    Jdk8之lambda表达式的使用及流式算法
  • 原文地址:https://www.cnblogs.com/gabin/p/13754039.html
Copyright © 2011-2022 走看看