This section mainly introduces the in-depth learning of spring boot application class related source code.
It mainly includes:
- Spring boot application custom boot configuration
- Spring boot application life cycle, as well as customized configuration in various stages of the life cycle.
This section uses springboot 2.1.10.release. The corresponding sample source code is: https://github.com/laolunsi/spring-boot-examples
SpringBoot application startup process:
SpringApplication application = new SpringApplication(DemoApplication.class); application.run(args);
I. Application class custom startup configuration
After creating the SpringApplication object, before calling the run method, we can use the SpringApplication object to add some configurations, such as disabling banner, setting the application type, and setting the profile
Give an example:
@SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication application = new SpringApplication(DemoApplication.class); // Set banner disable application.setBannerMode(Banner.Mode.OFF); // Enable application test file as profile application.setAdditionalProfiles("test"); // Set the application type to NONE, i.e. close automatically after startup application.setWebApplicationType(WebApplicationType.NONE); application.run(args); } }
You can also use the SpringApplicationBuilder class to create SpringApplication objects. The builder class provides an API for chain call, which is more convenient to call and enhances readability.
new SpringApplicationBuilder(YqManageCenterApplication.class) .bannerMode(Banner.Mode.OFF) .profiles("test") .web(WebApplicationType.NONE) .run(args);
II. application life cycle
The life cycle of spring application mainly includes:
- Preparation stage: mainly including loading configuration, setting main bean source, inferring Application type (three kinds), creating and setting SpringBootInitializer, creating and setting Application listener, inferring main entry class
- Running stage: start time listening, load running listener, create Environment, print banner, create and load context, broadcast application started, broadcast application running
Let's first look at the source code analysis:
SpringBootApplication Builder:
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { // Set default configuration 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.resourceLoader = resourceLoader; Assert.notNull(primarySources, "PrimarySources must not be null"); // Set main bean source this.primarySources = new LinkedHashSet(Arrays.asList(primarySources)); // Infer and set application types (three types) this.webApplicationType = WebApplicationType.deduceFromClasspath(); // Creating and setting up the SpringBootInitializer this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class)); // Creating and setting up a SpringBoot listener this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class)); // Infer and set the main entry class this.mainApplicationClass = this.deduceMainApplicationClass(); }
SpringApplication.run method source code:
public ConfigurableApplicationContext run(String... args) { // Enable time monitoring StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList(); this.configureHeadlessProperty(); // Load the Spring application run listener SpringApplicationRunListeners listeners = this.getRunListeners(args); listeners.starting(); Collection exceptionReporters; try { // Create environment (including PropertySources and Profiles) ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments); this.configureIgnoreBeanInfo(environment); // Print banner Banner printedBanner = this.printBanner(environment); // Create context (different application types correspond to different contexts) context = this.createApplicationContext(); exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context); // Load context (IOC container is also initialized) this.prepareContext(context, environment, listeners, applicationArguments, printedBanner); // Call applicationContext.refresh this.refreshContext(context); // Empty method this.afterRefresh(context, applicationArguments); stopWatch.stop(); // Turn off time listening; this will calculate the full start time if (this.logStartupInfo) { (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch); } // Broadcast that the SpringBoot application has been started. All the started methods in the SpringBootApplicationRunListener will be called listeners.started(context); // Traverse all the implementation classes of ApplicationRunner and CommadnLineRunner, and execute their run methods this.callRunners(context, applicationArguments); } catch (Throwable var10) { this.handleRunFailure(context, var10, exceptionReporters, listeners); throw new IllegalStateException(var10); } try { // When broadcasting a spring boot application running, all the running methods in the SpringBootApplicationRunListener will be called listeners.running(context); return context; } catch (Throwable var9) { // When an exception occurs in run, handle the exception; call the failed method in the listener reporting the error, broadcast the application failed to start, and spread the exception out this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null); throw new IllegalStateException(var9); } }
III. user defined configuration of application life cycle
In the life cycle of spring application, we can also add some custom configurations.
The following configuration is mainly implemented by implementing the interface provided by Spring, then creating a new META-INF/spring.factories file under resources, and adding this class in it.
In the preparation phase, you can add the following custom configurations:
3.1 implementation class of custom ApplicationContextInitializer
@Order(100) public class MyInitializer implements ApplicationContextInitializer { @Override public void initialize(ConfigurableApplicationContext configurableApplicationContext) { System.out.println("Custom application context initializer:" + configurableApplicationContext.toString()); } }
Define another My2Initializer and set @ Order(101)
Then configure the following in the spring.factories file:
# initializers org.springframework.context.ApplicationContextInitializer=\ com.example.applicationdemo.MyInitializer,\ com.example.applicationdemo.My2Initializer
Start project:
3.2 implementation class of custom ApplicationListener
@FunctionalInterface public interface ApplicationListener<E extends ApplicationEvent> extends EventListener { void onApplicationEvent(E var1); }![file](https://image-static.segmentfault.com/140/336/1403360350-5ddb5f8a5ab9d_articlex)
That is, the implementation class of the ApplicationListener interface listening to the ApplicationEvents class.
First, see how many kinds of ApplicationEvents are available:
It can also be split.
We set two applicationlisteners here to listen to ApplicationEnvironmentPreparedEvent
@Order(200) public class MyApplicationListener implements ApplicationListener<ApplicationEnvironmentPreparedEvent> { @Override public void onApplicationEvent(ApplicationEnvironmentPreparedEvent applicationEnvironmentPreparedEvent) { System.out.println("MyApplicationListener: Application environment ready" + applicationEnvironmentPreparedEvent.toString()); } }
Add the configuration of applicationListener in spring.factories:
# application-listeners org.springframework.context.ApplicationListener=\ com.example.applicationdemo.MyApplicationListener,\ com.example.applicationdemo.MyApplicationListener2
In the startup phase, you can add the following custom configurations:
3.3 implementation class of custom SpringBootRunListener
Monitor the whole spring boot application life cycle
public interface SpringApplicationRunListener { // Application startup void starting(); // The ConfigurableEnvironment is ready to be applied and can be adjusted at this time void environmentPrepared(ConfigurableEnvironment environment); // Context ready void contextPrepared(ConfigurableApplicationContext context); // Context load complete void contextLoaded(ConfigurableApplicationContext context); // Start up complete (Beans loaded into container) void started(ConfigurableApplicationContext context); // Application running void running(ConfigurableApplicationContext context); // App failed to run void failed(ConfigurableApplicationContext context, Throwable exception); }
We can customize the implementation class of SpringApplicationRunListener and define our own listener by overriding the above methods.
For example:
public class MyRunListener implements SpringApplicationRunListener { // Note that this constructor should be added. Neither of the two parameters should be less. Otherwise, the startup will report an error. For details of the error, see the bottom of this class public MyRunListener(SpringApplication springApplication, String[] args) { } @Override public void starting() { System.out.println("MyRunListener: Program start"); } // Other methods are omitted without modification }
Then add this class in the spring.factories file:
org.springframework.boot.SpringApplicationRunListener=\ com.example.applicationdemo.MyRunListener
Start up:
3.4 customize ApplicationRunner or CommandLineRunner
In the application run method, there is a line like this:
this.callRunners(context, applicationArguments);
After careful analysis of the source code, it is found that the function of this sentence is: during the startup of spring boot application, all application runners and commandlinerunners will be traversed to execute their run methods.
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); } } }
@FunctionalInterface public interface CommandLineRunner { void run(String... args) throws Exception; }
@FunctionalInterface public interface ApplicationRunner { void run(ApplicationArguments args) throws Exception; }
Define an implementation class and add @ Component. These two implementation classes do not need to be configured in spring.factories.
OK, about the specific use of these custom configurations, we will continue to introduce them later, please keep watching! Thank!
Please go to https://github.com/laolunsi/spring-boot-examples See.
Communication learning
Personal website: http://www.eknown.cn
GitHub: https://github.com/laolunsi
Public number: apes story, "sharing technology, and understanding life", welcome attention!