Detailed explanation of SpringBoot startup principle

1, Let's talk about the starting principle of SpringBoot

Open the startup class. After debugging, you can find that the startup of spingboot is divided into two parts:
1 create SpringApplication object
2 Run method

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

Start with creating objects

 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();
    }

The above is the creation process of spring application object
Mainly look at the last three lines (other codes are mainly some property settings)

this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
---->
Commissioning enters successively
this.getSpringFactoriesInstances()
loadFactoryNames()
loadSpringFactories()
classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
Click facts? Resource? Location to find the following
FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
In summary, find all applicationcontextinitializers from the class path META-INF/spring.factories through the getSpringFactoriesInstances() method and save them

Similarly, the second is to find all SpringApplicationRunListeners from the classpath through the getSpringFactoriesInstances() method

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

From the multiple configuration classes obtained, find the configuration main class (and the main configuration class can be configured with multiple classes), and return, so far, the SpringApplication object is created

this.mainApplicationClass = this.deduceMainApplicationClass();
----->
//From the obtained configuration classes, find the main configuration class containing the main method, and return
 for(int var4 = 0; var4 < var3; ++var4) {
                StackTraceElement stackTraceElement = var2[var4];
                if ("main".equals(stackTraceElement.getMethodName())) {
                    return Class.forName(stackTraceElement.getClassName());
                }
//Multiple main configuration classes can be configured
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
        return (new SpringApplication(primarySources)).run(args);
    }

Second, run the run method

public ConfigurableApplicationContext run(String... args) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
        //Configure the configuration related to AWT application  
        /*
          private void configureHeadlessProperty() {
        System.setProperty("java.awt.headless", System.getProperty("java.awt.headless", Boolean.toString(this.headless)));
    }
 */     
       this.configureHeadlessProperty();
        //Get the SpringApplicationRunListeners listener
        /*
         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);
        //Callback gets all springapplicationrunlisteners and executes the starting method
        listeners.starting();
        //Used for exception report analysis
        Collection exceptionReporters;
        try {
        //Encapsulate command line parameters
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
        //Prepare the environment,
        /* 
Get all SpringApplicationRunListener and call the environmentPrepared() method listeners.environmentPrepared((ConfigurableEnvironment)environment);

        */
            ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
            this.configureIgnoreBeanInfo(environment);
            //Spring will be printed here on the console
            Banner printedBanner = this.printBanner(environment);
            //Create IOC container
            /*
            1 Determine IOC container for
            2 Using reflection to create corresponding IOC container
            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();
            //Used for exception analysis report
            exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
            //Prepare the context environment and add the environment to the IOC container
            /*
            1 Call back the initialization method initial of all applicationcontext initialize rs saved before
            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 Call back the contextPrepared method of all previously saved SpringApplicationRunListener
    listeners.contextPrepared(context);
    ----->
     void contextPrepared(ConfigurableApplicationContext context) {
        Iterator var2 = this.listeners.iterator();

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

    }
    3 Finally, the SpringApplicationRunListener listens to the object and executes the contextLoaded method to load on behalf of the container
            */
            this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
            //Refresh container, IOC container initialization process, load all components, and Web
          // The application also loads the embedded Tomcat container here
            this.refreshContext(context);
            //Empty method
            this.afterRefresh(context, applicationArguments);
            stopWatch.stop();
            if (this.logStartupInfo) {
                (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
            }

            listeners.started(context);
            //From the IOC container, get the ApplicationRunner and ComandLineRunner classes
            //And call back the callRunner method
            /*
 private void callRunner(ApplicationRunner runner, ApplicationArguments args) {
        try {
            runner.run(args);
        } catch (Exception var4) {
            throw new IllegalStateException("Failed to execute ApplicationRunner", var4);
        }
    }
    Run the event listener
*/
            this.callRunners(context, applicationArguments);
        } catch (Throwable var10) {
            this.handleRunFailure(context, var10, exceptionReporters, listeners);
            throw new IllegalStateException(var10);
        }

        try {
        //Traverse springapplicationrunlistener and call back the method running(),
            listeners.running(context);
            //Return IOC container object, and spring boot application starts
            return context;
        } catch (Throwable var9) {
            this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
            throw new IllegalStateException(var9);
        }
    }

96 original articles published, 45 praised, 20000 visitors+
Private letter follow

Tags: Spring Java SpringBoot Tomcat

Posted on Fri, 31 Jan 2020 03:44:55 -0800 by Ab