SpringBoot boot class entry

The most intuitive difference between SpringBoot and Spring is that SpringBoot has its own independent boot class.

@SpringBootApplicationpublic class App {    public static void main(String[] args) {        SpringApplication.run(App.class, args);    }}
Copy the code

As you can see from the code above, the Annotation definition (@SpringBootApplication) and the class definition (springApplication.run ()) are the two essentials of SpringBoot startup.

SpringBoot startup principle and general related process

What does the @SpringBootApplication annotation do

@springBootApplication Annotation process is as follows:

The @SpringBootApplication annotations and core functionality are mainly accomplished by the following three child annotations

  • @ComponentScan
  • @SpringBootConfiguration
  • @EnableAutoConfiguration

@ComponentScan

@ComponentScan basically defines the path for scanning to find classes that identify the need to be assembled automatically into Spring’s bean container.

Those of you who have done web development have used the @Controller, @Service, and @repository annotations. If you look at the source code, there is a common annotation @Component, Yes, the @ComponentScan annotation will by default assemble classes that identify the @Controller, @Service, @Repository, and @Component annotations into the Spring container.

  • Add the @Controller, @Service, @Repository, and @Component annotations to the spring container below the custom scan path
  • Add classes that do not have the above annotations in the scan path to the Spring container through includeFilters
  • Filter out classes that do not need to be added to the Spring container through excludeFilters
  • Custom added annotation method for @Component annotation

@SpringBootConfiguration

@SpringBootConfiguration inherits from @Configuration and has the same functionality, marking the current class as a Configuration class and incorporating into the Spring container one or more instances of methods declared in the current class marked with the @Bean annotation, and instance names being method names.

@EnableAutoConfiguration

In a nutshell, @enableAutoConfiguration collects and registers scenario-specific bean definitions with @import support.

  • @enablescheduling loads Spring scheduling-framework related bean definitions into the IoC container via @import.
  • @enablembeanExport loads jMX-related bean definitions into the IoC container via @import.

@enableAutoConfiguration loads all auto-configured bean definitions into the IoC container with the help of @import, and that’s it!

As a composite Annotation, @enableAutoConfiguration defines the key information as follows:

@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import({AutoConfigurationImportSelector.class}) public @interface EnableAutoConfiguration { String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration"; Class<? >[] exclude() default {}; String[] excludeName() default {}; }Copy the code

One of the most critical is @ Import (AutoConfigurationImportSelector. Class), with the aid of AutoConfigurationImportSelector, @enableAutoConfiguration helps SpringBoot applications load all eligible @Configuration configurations into the IoC container currently created and used by SpringBoot.

The behind-the-scenes implementation of automatic configuration relies on the SpringFactoriesLoader, which is a proprietary extension of the Spring framework. The main function is to load the configuration from the specified configuration file meta-INF/Spring.Factories.

Used in conjunction with @enableAutoConfiguration, it provides more of a configuration lookup feature, According to the full name of the class of the @ EnableAutoConfiguration org. Springframework. Boot. Autoconfigure. EnableAutoConfiguration as a lookup Key, obtain corresponding to a set of @ Configura Tion classes.

@enableAutoConfiguration Is automatically configured to: Search all meta-INF/Spring. factories configuration files from the classpath, And will the org. Springframework. Boot. Autoconfigure. EnableutoConfiguration corresponding configuration items through reflection (Java Refletion) instantiated into the corresponding IoC container Configuration class in JavaConfig form annotated with @Configuration, then aggregated into one and loaded into the IoC container.

Springapplication.run () executes the process

Initialize SpringApplication

The SpringApplication constructor first initializes the SpringApplication:

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

1. Infer WebApplicationType, the main idea being to search for specific classes in the current classpath

2. Call getSpringFactoriesInstances from spring. Factories find key file for ApplicationContextInitializer class and instantiation, Then call the setInitializers method to set this up in the initializers property of the SpringApplication.

Search meta-inf \ spring factories file configuration ApplicationContextInitializer implementation class

3. Call getSpringFactoriesInstances from spring. Factories files to find the key for the ApplicationListener class and instantiation, Then call the setListeners method to the Listeners property of the SpringApplication. The process is to find all the application event listeners.

Search the implementation class of ApplicationListener configured in the meta-INF \spring.factories file

4. Call deduceMainApplicationClass method to find the main class, is SpringBootDemoApplication class here

private Class<? > deduceMainApplicationClass() { try { StackTraceElement[] stackTrace = (new RuntimeException()).getStackTrace(); StackTraceElement[] var2 = stackTrace; int var3 = stackTrace.length; for(int var4 = 0; var4 < var3; ++var4) { StackTraceElement stackTraceElement = var2[var4]; if ("main".equals(stackTraceElement.getMethodName())) { return Class.forName(stackTraceElement.getClassName()); } } } catch (ClassNotFoundException var6) { } return null; }Copy the code

Run SpringApplication

Run method

public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList(); this.configureHeadlessProperty(); SpringApplicationRunListeners listeners = this.getRunListeners(args); listeners.starting(); Collection exceptionReporters; try { ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments); this.configureIgnoreBeanInfo(environment); Banner printedBanner = this.printBanner(environment); context = this.createApplicationContext(); exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context); this.prepareContext(context, environment, listeners, applicationArguments, printedBanner); this.refreshContext(context); this.afterRefresh(context, applicationArguments); stopWatch.stop(); if (this.logStartupInfo) { (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch); } listeners.started(context); this.callRunners(context, applicationArguments); } catch (Throwable var10) { this.handleRunFailure(context, var10, exceptionReporters, listeners); throw new IllegalStateException(var10); } try { listeners.running(context); return context; } catch (Throwable var9) { this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null); throw new IllegalStateException(var9); }}Copy the code

After the run method has been executed, the Spring container has been initialized and the various listeners and initializers have done their work. See below for an analysis of specific steps.

Configure and prepare the environment:

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) { ConfigurableEnvironment environment = this.getOrCreateEnvironment(); this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs()); ConfigurationPropertySources.attach((Environment)environment); listeners.environmentPrepared((ConfigurableEnvironment)environment); this.bindToSpringApplication((ConfigurableEnvironment)environment); if (! this.isCustomEnvironment) { environment = (new EnvironmentConverter(this.getClassLoader())).convertEnvironmentIfNecessary((ConfigurableEnvironment)environment, this.deduceEnvironmentClass()); } ConfigurationPropertySources.attach((Environment)environment); return (ConfigurableEnvironment)environment; }Copy the code

Create a Spring container context:

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); }Copy the code

Configuring the Spring container context:

private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) { context.setEnvironment(environment); this.postProcessApplicationContext(context); this.applyInitializers(context); listeners.contextPrepared(context); if (this.logStartupInfo) { this.logStartupInfo(context.getParent() == null); this.logStartupProfileInfo(context); } ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); beanFactory.registerSingleton("springApplicationArguments", applicationArguments); if (printedBanner ! = null) { beanFactory.registerSingleton("springBootBanner", printedBanner); } if (beanFactory instanceof DefaultListableBeanFactory) { ((DefaultListableBeanFactory)beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding); } if (this.lazyInitialization) { context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor()); } Set<Object> sources = this.getAllSources(); Assert.notEmpty(sources, "Sources must not be empty"); this.load(context, sources.toArray(new Object[0])); listeners.contextLoaded(context); }Copy the code

After the Spring container creates postProcessApplicationContext callback methods:

protected void postProcessApplicationContext(ConfigurableApplicationContext context) { if (this.beanNameGenerator ! = null) { context.getBeanFactory().registerSingleton("org.springframework.context.annotation.internalConfigurationBeanNameGenerato r", this.beanNameGenerator); } if (this.resourceLoader ! = null) { if (context instanceof GenericApplicationContext) { ((GenericApplicationContext)context).setResourceLoader(this.resourceLoader); } if (context instanceof DefaultResourceLoader) { ((DefaultResourceLoader)context).setClassLoader(this.resourceLoader.getClassLoader()); } } if (this.addConversionService) { context.getBeanFactory().setConversionService(ApplicationConversionService.getSharedInstance()); }}Copy the code

Once the Spring container is created, the callRunners method is called:

private void callRunners(ApplicationContext context, ApplicationArguments args) { List<Object> runners = new ArrayList(); runners.addAll(context.getBeansOfType(ApplicationRunner.class).values()); runners.addAll(context.getBeansOfType(CommandLineRunner.class).values()); AnnotationAwareOrderComparator.sort(runners); Iterator var4 = (new LinkedHashSet(runners)).iterator(); while(var4.hasNext()) { Object runner = var4.next(); if (runner instanceof ApplicationRunner) { this.callRunner((ApplicationRunner)runner, args); } if (runner instanceof CommandLineRunner) { this.callRunner((CommandLineRunner)runner, args); }}}Copy the code

Reference article:

www.cnblogs.com/theRhyme/p/…

Blog. Wangqi. Love/articles/Sp…