ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

SpringBoot启动原理详解

2020-01-31 18:36:45  阅读:187  来源: 互联网

标签:SpringBoot args class listeners 详解 context new 原理 Class


一,本篇来说说SpringBoot的启动原理

打开启动类,调试进入可以发现SpirngBoot的启动分为两部分:
1创建SpringApplication对象
2运行Run方法

 public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
        return (new SpringApplication(primarySources)).run(args);
    }

先从创建对象讲起

 public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {

        this.sources = new LinkedHashSet();
        this.bannerMode = Mode.CONSOLE;
        this.logStartupInfo = true;
        this.addCommandLineProperties = true;
        this.addConversionService = true;
        this.headless = true;
        this.registerShutdownHook = true;
        this.additionalProfiles = new HashSet();
        this.isCustomEnvironment = false;
        this.lazyInitialization = false;
        this.resourceLoader = resourceLoader;
        Assert.notNull(primarySources, "PrimarySources must not be null");
        this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
        this.webApplicationType = WebApplicationType.deduceFromClasspath();
        this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
        this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
        this.mainApplicationClass = this.deduceMainApplicationClass();
    }

上面即是SpringApplication对象的创建过程
主要看最后面三行(其他代码主要是一些属性设置)


this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
---->
调试依次进入
this.getSpringFactoriesInstances()
loadFactoryNames()
loadSpringFactories()
classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
点击FACTORIES_RESOURCE_LOCATION即可有如下发现
FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
总结,通过getSpringFactoriesInstances()方法从类路径META-INF/spring.factories找到所有的ApplicationContextinitializer然后保存起来

同理第二个,同样是通过getSpringFactoriesInstances()方法从类路径下找到所有的SpringApplicationRunListeners

this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));

从获取的多个配置类中,找到配置主类(且主配置类可配置多个),并返回,至此,SpringApplication对象就创建完成了

this.mainApplicationClass = this.deduceMainApplicationClass();
----->
//从获取的多个配置类中,找到包含main方法的主配置类,然后返回
 for(int var4 = 0; var4 < var3; ++var4) {
                StackTraceElement stackTraceElement = var2[var4];
                if ("main".equals(stackTraceElement.getMethodName())) {
                    return Class.forName(stackTraceElement.getClassName());
                }
//可配置多个主配置类
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
        return (new SpringApplication(primarySources)).run(args);
    }

第二步,运行run方法

public ConfigurableApplicationContext run(String... args) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
        //配置与AWT应用相关的配置  
        /*
          private void configureHeadlessProperty() {
        System.setProperty("java.awt.headless", System.getProperty("java.awt.headless", Boolean.toString(this.headless)));
    }
 */     
       this.configureHeadlessProperty();
        //获取SpringApplicationRunListeners监听器
        /*
         private SpringApplicationRunListeners getRunListeners(String[] args) {
        Class<?>[] types = new Class[]{SpringApplication.class, String[].class};
        return new SpringApplicationRunListeners(logger, this.getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
    }*/
        SpringApplicationRunListeners listeners = this.getRunListeners(args);
        //回调获取所有的SpringApplicationRunListener并执行starting方法
        listeners.starting();
        //用来做异常报告分析
        Collection exceptionReporters;
        try {
        //封装命令行参数
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
        //准备环境,
        /* 
获取所有的SpringApplicationRunListener并回调environmentPrepared()方法        listeners.environmentPrepared((ConfigurableEnvironment)environment);

        */
            ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
            this.configureIgnoreBeanInfo(environment);
            //此处会在控制台打印Spring
            Banner printedBanner = this.printBanner(environment);
            //创建IOC容器
            /*
            1确定对于的IOC容器
            2利用反射创建对应的IOC容器
            protected ConfigurableApplicationContext createApplicationContext() {
        Class<?> contextClass = this.applicationContextClass;
        if (contextClass == null) {
            try {
                switch(this.webApplicationType) {
                case SERVLET:
                    contextClass = Class.forName("org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext");
                    break;
                case REACTIVE:
                    contextClass = Class.forName("org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext");
                    break;
                default:
                    contextClass = Class.forName("org.springframework.context.annotation.AnnotationConfigApplicationContext");
                }
            } catch (ClassNotFoundException var3) {
                throw new IllegalStateException("Unable create a default ApplicationContext, please specify an ApplicationContextClass", var3);
            }
        }

        return (ConfigurableApplicationContext)BeanUtils.instantiateClass(contextClass);
    }
            */
            context = this.createApplicationContext();
            //用来做异常分析报告
            exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
            //准备上下文环境,将environment加入到IOC容器中
            /*
            1 回调之前保存的所有的ApplicationContextInitializer的initialize方法初始
            this.applyInitializers(context);
            ---->
             protected void applyInitializers(ConfigurableApplicationContext context) {
        Iterator var2 = this.getInitializers().iterator();

        while(var2.hasNext()) {
            ApplicationContextInitializer initializer = (ApplicationContextInitializer)var2.next();
            Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(), ApplicationContextInitializer.class);
            Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
            initializer.initialize(context);
        }

####################
//2回调之前保存的所有的SpringApplicationRunListener的contextPrepared方法
    listeners.contextPrepared(context);
    ----->
     void contextPrepared(ConfigurableApplicationContext context) {
        Iterator var2 = this.listeners.iterator();

        while(var2.hasNext()) {
            SpringApplicationRunListener listener = (SpringApplicationRunListener)var2.next();
            listener.contextPrepared(context);
        }

    }
    3最后SpringApplicationRunListener监听对象执行contextLoaded方法代表容器加载完成
            */
            this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
            //刷新容器,IOC容器的初始化过程,加载所有的组件,且Web
          // 应用也是在此处加载嵌入式Tomcat容器
            this.refreshContext(context);
            //空方法
            this.afterRefresh(context, applicationArguments);
            stopWatch.stop();
            if (this.logStartupInfo) {
                (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
            }

            listeners.started(context);
            //从IOC容器中,获取ApplicationRunner和ComandLineRunner类
            //并回调callRunner方法
            /*
 private void callRunner(ApplicationRunner runner, ApplicationArguments args) {
        try {
            runner.run(args);
        } catch (Exception var4) {
            throw new IllegalStateException("Failed to execute ApplicationRunner", var4);
        }
    }
    运行该事件监听器
*/
            this.callRunners(context, applicationArguments);
        } catch (Throwable var10) {
            this.handleRunFailure(context, var10, exceptionReporters, listeners);
            throw new IllegalStateException(var10);
        }

        try {
        //遍历SpringApplicationRunListenen,并回调方法running(),
            listeners.running(context);
            //返回IOC容器对象,SpringBoot应用启动
            return context;
        } catch (Throwable var9) {
            this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
            throw new IllegalStateException(var9);
        }
    }

Rapper_cl 发布了96 篇原创文章 · 获赞 45 · 访问量 2万+ 私信 关注

标签:SpringBoot,args,class,listeners,详解,context,new,原理,Class
来源: https://blog.csdn.net/m0_37510446/article/details/104124701

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有