spring boot 原理:生命周期
引子
Spring应用?
SpringApplication
启动为什么要传入主类?
启动前可以做什么?
可以继承SpringApplication 重写protected方法;
new SpringApplication 实例后,调用set方法修改默认配置,再run;
或者工厂模式SpringApplicationBuilder修改默认配置后run;
或者通过 META-INF/spring.factories文件自动化配置;
尽管平时调用的run是静态方法,但实际等同与上面,先要new SpringApplication ,再调用实例方法 org.springframework.boot.SpringApplication.run(String...)
慎用懒加载,这个只会提高启动速度,但是隐藏的风险很大,比如一些bean只有web请求时才会触发初始化
An application is considered live as soon as the context has been refreshed, see Spring Boot application lifecycle and related Application Events.
An application is considered ready as soon as application and command-line runners have been called, see Spring Boot application lifecycle and related Application Events.
整体流程
Environment
new StandardServletEnvironment() 这个实例化都做了什么?
有什么骚操作?
什么是env?
AbstractEnvironment 提供了org.springframework.core.env.AbstractEnvironment.customizePropertySources(MutablePropertySources)
没有做操作,子类可以重写该方法
因为实例化子类必须按顺序实例化所有超类,骚操作是实例化最终超类AbstractEnvironment 时,它调用了customizePropertySources 方法,
这一步实际会调用子类的重写方法,即org.springframework.web.context.support.StandardServletEnvironment.customizePropertySources(MutablePropertySources),
而该方法中添加完毕资源后还会调用父类的该方法即 org.springframework.core.env.StandardEnvironment.customizePropertySources(MutablePropertySources)
一顿操作下来,StandardServletEnvironment 添加了 servletConfigInitParams、servletContextInitParams、jndiProperties
StandardEnvironment添加了 systemProperties、systemEnvironment
另个init 方法会在context 刷新时调用 对应⑥
@Override protected void initPropertySources() { ConfigurableEnvironment env = getEnvironment(); if (env instanceof ConfigurableWebEnvironment) { ((ConfigurableWebEnvironment) env).initPropertySources(this.servletContext, null); } }
env 和 prop 区别是什么?env 不允许修改,prop允许修改,比如可以通过-D指定,以下实际测试输出:
public static void main(String[] args) throws Exception { System.out.println(JSONObject.toJSONString(System.getenv(),SerializerFeature.PrettyFormat,SerializerFeature.MapSortField)); System.out.println(JSONObject.toJSONString(System.getProperties(),SerializerFeature.PrettyFormat,SerializerFeature.MapSortField)); }
{ "=::":"::\\", "ALLUSERSPROFILE":"C:\\ProgramData", "APPDATA":"C:\\Users\\witas\\AppData\\Roaming", "COMPUTERNAME":"DESKTOP-5KL2IOV", "ComSpec":"C:\\WINDOWS\\system32\\cmd.exe", "CommonProgramFiles":"C:\\Program Files\\Common Files", "CommonProgramFiles(x86)":"C:\\Program Files (x86)\\Common Files", "CommonProgramW6432":"C:\\Program Files\\Common Files", "DriverData":"C:\\Windows\\System32\\Drivers\\DriverData", "FPS_BROWSER_APP_PROFILE_STRING":"Internet Explorer", "FPS_BROWSER_USER_PROFILE_STRING":"Default", "HOMEDRIVE":"C:", "HOMEPATH":"\\Users\\witas", "JAVA_HOME":"D:\\e\\Java\\openjdk1.8.0_181", "LOCALAPPDATA":"C:\\Users\\witas\\AppData\\Local", "LOGONSERVER":"\\\\DESKTOP-5KL2IOV", "MAVEN_HOME":"D:\\e\\maven\\apache-maven-3.6.0", "NLS_LANG":"SIMPLIFIED CHINESE_CHINA.ZHS16GBK", "NUMBER_OF_PROCESSORS":"8", "ORACLE_HOME":"D:\\e\\oracle\\instantclient_11_2", "OS":"Windows_NT", "OneDrive":"C:\\Users\\witas\\OneDrive", "OneDriveConsumer":"C:\\Users\\witas\\OneDrive", "PATHEXT":".COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC", "PROCESSOR_ARCHITECTURE":"AMD64", "PROCESSOR_IDENTIFIER":"Intel64 Family 6 Model 142 Stepping 10, GenuineIntel", "PROCESSOR_LEVEL":"6", "PROCESSOR_REVISION":"8e0a", "PSModulePath":"C:\\Program Files\\WindowsPowerShell\\Modules;...", "PUBLIC":"C:\\Users\\Public", "Path":"C:\\Program Files (x86)\\Common Files\\Oracle\\Java\\javapath;...", "ProgramData":"C:\\ProgramData", "ProgramFiles":"C:\\Program Files", "ProgramFiles(x86)":"C:\\Program Files (x86)", "ProgramW6432":"C:\\Program Files", "SESSIONNAME":"Console", "SystemDrive":"C:", "SystemRoot":"C:\\WINDOWS", "TEMP":"C:\\Users\\witas\\AppData\\Local\\Temp", "TMP":"C:\\Users\\witas\\AppData\\Local\\Temp", "TNS_ADMIN":"D:\\e\\oracle\\tnsnames", "USERDOMAIN":"DESKTOP-5KL2IOV", "USERDOMAIN_ROAMINGPROFILE":"DESKTOP-5KL2IOV", "USERNAME":"witas", "USERPROFILE":"C:\\Users\\witas", "windir":"C:\\WINDOWS" }
{ "awt.toolkit":"sun.awt.windows.WToolkit", "file.encoding":"UTF-8", "file.encoding.pkg":"sun.io", "file.separator":"\\", "java.awt.graphicsenv":"sun.awt.Win32GraphicsEnvironment", "java.awt.printerjob":"sun.awt.windows.WPrinterJob", "java.class.path":"...", "java.class.version":"52.0", "java.endorsed.dirs":"D:\\e\\Java\\openjdk1.8.0_181\\jre\\lib\\endorsed", "java.ext.dirs":"D:\\e\\Java\\openjdk1.8.0_181\\jre\\lib\\ext;C:\\WINDOWS\\Sun\\Java\\lib\\ext", "java.home":"D:\\e\\Java\\openjdk1.8.0_181\\jre", "java.io.tmpdir":"C:\\Users\\witas\\AppData\\Local\\Temp\\", "java.library.path":"D:\\e\\Java\\openjdk1.8.0_181\\bin;...", "java.runtime.name":"OpenJDK Runtime Environment", "java.runtime.version":"1.8.0_181-1-redhat-b13", "java.specification.name":"Java Platform API Specification", "java.specification.vendor":"Oracle Corporation", "java.specification.version":"1.8", "java.vendor":"Oracle Corporation", "java.vendor.url":"http://java.oracle.com/", "java.vendor.url.bug":"http://bugreport.sun.com/bugreport/", "java.version":"1.8.0_181-1-redhat", "java.vm.info":"mixed mode", "java.vm.name":"OpenJDK 64-Bit Server VM", "java.vm.specification.name":"Java Virtual Machine Specification", "java.vm.specification.vendor":"Oracle Corporation", "java.vm.specification.version":"1.8", "java.vm.vendor":"Oracle Corporation", "java.vm.version":"25.181-b13", "line.separator":"\r\n", "os.arch":"amd64", "os.name":"Windows 10", "os.version":"10.0", "path.separator":";", "sun.arch.data.model":"64", "sun.boot.class.path":"D:\\e\\Java\\openjdk1.8.0_181\\jre\\lib\\resources.jar;....", "sun.boot.library.path":"D:\\e\\Java\\openjdk1.8.0_181\\jre\\bin", "sun.cpu.endian":"little", "sun.cpu.isalist":"amd64", "sun.desktop":"windows", "sun.io.unicode.encoding":"UnicodeLittle", "sun.java.command":"cn.zno.springbootwebminimal.CC", "sun.java.launcher":"SUN_STANDARD", "sun.jnu.encoding":"GBK", "sun.management.compiler":"HotSpot 64-Bit Tiered Compilers", "sun.os.patch.level":"", "user.country":"CN", "user.dir":"D:\\e\\svn\\repo1\\原型\\springbootwebminimal", "user.home":"C:\\Users\\witas", "user.language":"zh", "user.name":"witas", "user.script":"", "user.timezone":"Asia/Shanghai", "user.variant":"" }
什么是evn,org.springframework.core.env.Environment 给出了解释:
Interface representing the environment in which the current application is running. Models two key aspects of the application environment: profiles and properties. Methods related to property access are exposed via the PropertyResolver super interface. A profile is a named, logical group of bean definitions to be registered with the container only if the given profile is active. Beans may be assigned to a profile whether defined in XML or via annotations; see the spring-beans 3.1 schemaor the @Profile annotation for syntax details. The role of the Environment object with relation to profiles is in determining which profiles (if any) are currently active, and which profiles (if any) should be active by default. Properties play an important role in almost all applications, and may originate from a variety of sources: properties files, JVM system properties, system environment variables, JNDI, servlet context parameters, ad-hoc Properties objects,Maps, and so on. The role of the environment object with relation to properties is to provide the user with a convenient service interface for configuring property sources
and resolving properties from them. Beans managed within an ApplicationContext may register to be EnvironmentAware or @Inject the Environment in order to query profile state or resolve properties directly. In most cases, however, application-level beans should not need to interact with the Environment directly but instead may have to have ${...}} property values
replaced by a property placeholder configurer such as PropertySourcesPlaceholderConfigurer,
which itself is EnvironmentAware and as of Spring 3.1 is registered by default when using <context:property-placeholder/>. Configuration of the environment object must be done through the ConfigurableEnvironment interface, returned from all AbstractApplicationContext subclass getEnvironment() methods. See ConfigurableEnvironment Javadoc for usage examples demonstrating manipulation of property sources prior to application context refresh().
小结:env 是当前应用运行时所处的环境,主要管理profiles和properties ; Properties 来源有系统变量,环境变量,servlet上下文参数等
主类
启动为什么传入主类?它到底是什么?为什么传入非main函数所在类无法启动应用?
primarySource the primary source to load
primarySources the primary bean sources
The application context will loadbeans from the specified primary sources (see class-leveld ocumentation for details. The instance can be customized before calling run(String).
答:主类只要有@org.springframework.boot.autoconfigure.SpringBootApplication 注解即可,main函数可以在任意类中。
所以关键在于这个注解做了什么,先看该注解说明:
Indicates a configuration class that declares one or more @Bean methods and also triggers auto-configuration and component scanning. This is a convenienceannotation that is equivalent to declaring @Configuration, @EnableAutoConfiguration and @ComponentScan.
也就是说它等价于@Configuration + @EnableAutoConfiguration + @ComponentScan
就是说主资源是一个配置,这里开启了自动配置和组件扫描,无法启动是因为没有自动注入 ,判定的是web应用,但是在bean工厂没有找到ServletWebServerFactory 无法启动 ServletWebServerApplicationContext ,所以报错说
missing ServletWebServerFactory bean.
Uable to start ...
这个bean是 org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryConfiguration 中自动注入的
org.springframework.context.ApplicationContextException: Unable to start web server; nested exception is org.springframework.context.ApplicationContextException: Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean. at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:156) ~[spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE] at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:544) ~[spring-context-5.2.2.RELEASE.jar:5.2.2.RELEASE] at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:141) ~[spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE] at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:747) [spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE] at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) [spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE] at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) [spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226) [spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1215) [spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE] at cn.zno.springbootwebminimal.FooApplication.main(FooApplication.java:30) [classes/:na] Caused by: org.springframework.context.ApplicationContextException: Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean. at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.getWebServerFactory(ServletWebServerApplicationContext.java:203) ~[spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE] at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.createWebServer(ServletWebServerApplicationContext.java:179) ~[spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE] at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:153) ~[spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE] ... 8 common frames omitted
是依据具体条件要有Servlet、Tomcat和UpgradeProtocol 类,才激活。类似的还有 EmbeddedJetty和EmbeddedUndertow
@Configuration(proxyBeanMethods = false) @ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class }) @ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT) public static class EmbeddedTomcat { @Bean public TomcatServletWebServerFactory tomcatServletWebServerFactory( ObjectProvider<TomcatConnectorCustomizer> connectorCustomizers, ObjectProvider<TomcatContextCustomizer> contextCustomizers, ObjectProvider<TomcatProtocolHandlerCustomizer<?>> protocolHandlerCustomizers) { TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory(); factory.getTomcatConnectorCustomizers() .addAll(connectorCustomizers.orderedStream().collect(Collectors.toList())); factory.getTomcatContextCustomizers() .addAll(contextCustomizers.orderedStream().collect(Collectors.toList())); factory.getTomcatProtocolHandlerCustomizers() .addAll(protocolHandlerCustomizers.orderedStream().collect(Collectors.toList())); return factory; } }
refresh
protected void refresh(ApplicationContext applicationContext) { Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext); ((AbstractApplicationContext) applicationContext).refresh(); }
上面这个操作会调用最外层子类的重写方法,实际调用的是 org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh()
但是这里面有异常的时候处理了一下,只是调用了super.refresh() ,即org.springframework.context.support.AbstractApplicationContext.refresh()
具体内容如下:
@Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. prepareRefresh(); // Tell the subclass to refresh the internal bean factory. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. registerBeanPostProcessors(beanFactory); // Initialize message source for this context. initMessageSource(); // Initialize event multicaster for this context. initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. onRefresh(); // Check for listener beans and register them. registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. finishRefresh(); }
疑问:如何知道一个spring组件是在哪一步被实例化的?
思路:随便一个Component 构造函数打断点可知
关于 org.springframework.beans.factory.support.DefaultListableBeanFactory 完全可以单独介绍,到这里和spring framework 照面了
小结:在生命周期我可以做哪些事情
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class FooApplication { public static void main(String[] args) { System.out.println("run方法前"); SpringApplication app = new SpringApplication(new Class<?>[] { FooApplication.class }); app.setBanner(new MyBanner()); app.addListeners(new MyApplicationListener()); app.run(args); System.out.println("run方法后"); } }
可以监听事件
import org.springframework.context.ApplicationEvent; import org.springframework.context.ApplicationListener; public class MyApplicationListener implements ApplicationListener<ApplicationEvent> { @Override public void onApplicationEvent(ApplicationEvent event) { System.out.println("Event触发:" + event.getClass()); } }
可以设置banner
import java.io.PrintStream; import org.springframework.boot.Banner; import org.springframework.core.env.Environment; public class MyBanner implements Banner { @Override public void printBanner(Environment environment, Class<?> sourceClass, PrintStream printStream) { StringBuilder sb = new StringBuilder(); sb.append("\r\n "); sb.append(" ◢████████████◣ \r\n"); sb.append(" ██████████████ \r\n"); sb.append(" ██ ◥██◤ ██ \r\n"); sb.append(" ◢███ ◥◤ ██◣ \r\n"); sb.append(" ▊▎██◣ ◢█▊▊ \r\n"); sb.append(" ▊▎██◤ ● ● ◥█▊▊ \r\n"); sb.append(" ▊ ██ █▊▊ \r\n"); sb.append(" ◥▇██ ▊ ▊ █▇◤ \r\n"); sb.append(" ██ ◥▆▄▄▄▄▆◤ █▊ ◢▇▇◣ \r\n"); sb.append("◢██◥◥▆▅▄▂▂▂▂▄▅▆███◣ ▊◢ █ \r\n"); sb.append("█╳ ╳█ ◥◤◢◤ \r\n"); sb.append("◥█◣ ˙ ˙ ◢█◤ ◢◤ \r\n"); sb.append(" ▊ ▊ █ \r\n"); sb.append(" ▊ ▊ ◢◤ \r\n"); sb.append(" ▊ ⊕ █▇▇▇◤ \r\n"); sb.append(" ◢█▇▆▆▆▅▅▅▅▆▆▆▇█◣ \r\n"); sb.append(" ▊ ▂ ▊ ▊ ▂ \r\n\r\n"); printStream.print(sb); } }
import org.springframework.stereotype.Component; @Component public class MyComponent { { System.out.println("实例化MyComponent"); } }
可以执行runner(自动扫描)
import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; import org.springframework.stereotype.Component; import com.alibaba.fastjson.JSONObject; @Component public class MyApplicationRunner implements ApplicationRunner { @Override public void run(ApplicationArguments args) throws Exception { System.out.println("应用Runner触发:" + JSONObject.toJSONString(args)); } }
可以执行runner(自动扫描)
import org.springframework.boot.CommandLineRunner; import org.springframework.stereotype.Component; import com.alibaba.fastjson.JSONObject; @Component public class MyCommandLineRunner implements CommandLineRunner { @Override public void run(String... args) throws Exception { System.out.println("命令行runner触发:" + JSONObject.toJSONString(args)); } }
效果:
run方法前 Event触发:class org.springframework.boot.context.event.ApplicationStartingEvent Event触发:class org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent ◢████████████◣ ██████████████ ██ ◥██◤ ██ ◢███ ◥◤ ██◣ ▊▎██◣ ◢█▊▊ ▊▎██◤ ● ● ◥█▊▊ ▊ ██ █▊▊ ◥▇██ ▊ ▊ █▇◤ ██ ◥▆▄▄▄▄▆◤ █▊ ◢▇▇◣ ◢██◥◥▆▅▄▂▂▂▂▄▅▆███◣ ▊◢ █ █╳ ╳█ ◥◤◢◤ ◥█◣ ˙ ˙ ◢█◤ ◢◤ ▊ ▊ █ ▊ ▊ ◢◤ ▊ ⊕ █▇▇▇◤ ◢█▇▆▆▆▅▅▅▅▆▆▆▇█◣ ▊ ▂ ▊ ▊ ▂ Event触发:class org.springframework.boot.context.event.ApplicationContextInitializedEvent 2023-05-09 16:09:49.726 INFO 18224 --- [ main] c.z.springbootwebminimal.FooApplication : Starting FooApplication on DESKTOP-5KL2IOV with PID 18224 (started by witas in D:\e\svn\repo1\原型\springbootwebminimal) 2023-05-09 16:09:49.730 INFO 18224 --- [ main] c.z.springbootwebminimal.FooApplication : No active profile set, falling back to default profiles: default Event触发:class org.springframework.boot.context.event.ApplicationPreparedEvent 2023-05-09 16:09:51.095 INFO 18224 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http) 2023-05-09 16:09:51.107 INFO 18224 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2023-05-09 16:09:51.107 INFO 18224 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.29] 2023-05-09 16:09:51.181 INFO 18224 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2023-05-09 16:09:51.182 INFO 18224 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1401 ms 实例化MyComponent 2023-05-09 16:09:51.365 INFO 18224 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor' 2023-05-09 16:09:51.433 INFO 18224 --- [ main] o.s.b.a.w.s.WelcomePageHandlerMapping : Adding welcome page template: index 2023-05-09 16:09:51.482 WARN 18224 --- [ main] org.thymeleaf.templatemode.TemplateMode : [THYMELEAF][main] Template Mode 'HTML5' is deprecated. Using Template Mode 'HTML' instead. Event触发:class org.springframework.context.event.ContextRefreshedEvent 2023-05-09 16:09:51.553 INFO 18224 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '' Event触发:class org.springframework.boot.web.servlet.context.ServletWebServerInitializedEvent 2023-05-09 16:09:51.556 INFO 18224 --- [ main] c.z.springbootwebminimal.FooApplication : Started FooApplication in 2.239 seconds (JVM running for 2.624) Event触发:class org.springframework.boot.context.event.ApplicationStartedEvent 应用Runner触发:{"nonOptionArgs":[],"optionNames":[],"sourceArgs":[]} 命令行runner触发:[] Event触发:class org.springframework.boot.context.event.ApplicationReadyEvent run方法后
补充请求http之后和关闭jvm的日志
... run方法后 2023-05-09 16:27:09.990 INFO 15460 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet' 2023-05-09 16:27:09.990 INFO 15460 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet' 2023-05-09 16:27:09.994 INFO 15460 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 4 ms Event触发:class org.springframework.web.context.support.ServletRequestHandledEvent Event触发:class org.springframework.web.context.support.ServletRequestHandledEvent Event触发:class org.springframework.web.context.support.ServletRequestHandledEvent Event触发:class org.springframework.web.context.support.ServletRequestHandledEvent 2023-05-09 16:27:39.412 INFO 15460 --- [on(3)-127.0.0.1] inMXBeanRegistrar$SpringApplicationAdmin : Application shutdown requested. Event触发:class org.springframework.context.event.ContextClosedEvent 2023-05-09 16:27:39.414 INFO 15460 --- [on(3)-127.0.0.1] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor'
附1 :
spring-boot-2.2.2.RELEASE.jar中
META-INF/spring.factories
# PropertySource Loaders org.springframework.boot.env.PropertySourceLoader=\ org.springframework.boot.env.PropertiesPropertySourceLoader,\ org.springframework.boot.env.YamlPropertySourceLoader # Run Listeners org.springframework.boot.SpringApplicationRunListener=\ org.springframework.boot.context.event.EventPublishingRunListener # Error Reporters org.springframework.boot.SpringBootExceptionReporter=\ org.springframework.boot.diagnostics.FailureAnalyzers # Application Context Initializers org.springframework.context.ApplicationContextInitializer=\ org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\ org.springframework.boot.context.ContextIdApplicationContextInitializer,\ org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\ org.springframework.boot.rsocket.context.RSocketPortInfoApplicationContextInitializer,\ org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer # Application Listeners org.springframework.context.ApplicationListener=\ org.springframework.boot.ClearCachesApplicationListener,\ org.springframework.boot.builder.ParentContextCloserApplicationListener,\ org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\ org.springframework.boot.context.FileEncodingApplicationListener,\ org.springframework.boot.context.config.AnsiOutputApplicationListener,\ org.springframework.boot.context.config.ConfigFileApplicationListener,\ org.springframework.boot.context.config.DelegatingApplicationListener,\ org.springframework.boot.context.logging.ClasspathLoggingApplicationListener,\ org.springframework.boot.context.logging.LoggingApplicationListener,\ org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener # Environment Post Processors org.springframework.boot.env.EnvironmentPostProcessor=\ org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\ org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor,\ org.springframework.boot.env.SystemEnvironmentPropertySourceEnvironmentPostProcessor,\ org.springframework.boot.reactor.DebugAgentEnvironmentPostProcessor # Failure Analyzers org.springframework.boot.diagnostics.FailureAnalyzer=\ org.springframework.boot.diagnostics.analyzer.BeanCurrentlyInCreationFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.BeanDefinitionOverrideFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.BeanNotOfRequiredTypeFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.BindFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.BindValidationFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.UnboundConfigurationPropertyFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.ConnectorStartFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.NoSuchMethodFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.NoUniqueBeanDefinitionFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.PortInUseFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.ValidationExceptionFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyNameFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyValueFailureAnalyzer # FailureAnalysisReporters org.springframework.boot.diagnostics.FailureAnalysisReporter=\ org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter
附2:
-
An
ApplicationStartingEvent
is sent at the start of a run but before any processing, except for the registration of listeners and initializers. -
An
ApplicationEnvironmentPreparedEvent
is sent when theEnvironment
to be used in the context is known but before the context is created. -
An
ApplicationContextInitializedEvent
is sent when theApplicationContext
is prepared and ApplicationContextInitializers have been called but before any bean definitions are loaded. -
An
ApplicationPreparedEvent
is sent just before the refresh is started but after bean definitions have been loaded. -
An
ApplicationStartedEvent
is sent after the context has been refreshed but before any application and command-line runners have been called. -
An
AvailabilityChangeEvent
is sent right after withLivenessState.CORRECT
to indicate that the application is considered as live. -
An
ApplicationReadyEvent
is sent after any application and command-line runners have been called. -
An
AvailabilityChangeEvent
is sent right after withReadinessState.ACCEPTING_TRAFFIC
to indicate that the application is ready to service requests. -
An
ApplicationFailedEvent
is sent if there is an exception on startup.