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的版本来看,我差点没被搞死。。。第一次看还是老实点,看纯净版的

  • 相关阅读:
    OSG-提示“error reading file e:1.jpg file not handled”
    OSG-加载地球文件报0x00000005错误,提示error reading file simple.earth file not handled
    QT-找开工程后,最上方提示the code model could not parse an included file, which might lead to incorrect code completion and highlighting, for example.
    我的书《Unity3D动作游戏开发实战》出版了
    java中无符号类型的第三方库jOOU
    Windows批处理备份mysql数据
    使用 DevTools 时,通用Mapper经常会出现 class x.x.A cannot be cast to x.x.A
    Java版本,Java版本MongoDB驱动,驱动与MongoDB数据库,Spring之间的兼容性
    Jrebel本地激活方法
    wget下载指定网站目录下的所有内容
  • 原文地址:https://www.cnblogs.com/gabin/p/13754039.html
Copyright © 2011-2022 走看看