1、组件自动装配
(1)激活:@EnableAutoConfiguration
(2)配置:/META-INF/spring.factories (key-value形式)
(3)实现: XXXAutoConfiguration
2、嵌入式web容器
(1) Web Servlet: tomcat、jetty
(2) Web Reactive: Netty Web Server
3、生产准备特性
SpringApplication准备阶段
1、SpringApplication启动及推断源
@SpringBootApplication
public class SpringApplicationBootstrap {
public static void main(String[] args) {
SpringApplication.run(SpringApplicationBootstrap.class, args);
//SpringApplication.run(ApplicationConfiguration.class, args);
new SpringApplicationBuilder(SpringApplicationBootstrap.class)
.web(WebApplicationType.NONE)
.run(args);
}
// @SpringBootApplication
// public static class ApplicationConfiguration {
//
// }
}
2、推断Web应用类型
通过 SpringApplication中的方法判断
private static final String[] SERVLET_INDICATOR_CLASSES = new String[]{"javax.servlet.Servlet", "org.springframework.web.context.ConfigurableWebApplicationContext"};
static WebApplicationType deduceFromClasspath() {
if (ClassUtils.isPresent("org.springframework.web.reactive.DispatcherHandler", (ClassLoader)null) && !ClassUtils.isPresent("org.springframework.web.servlet.DispatcherServlet", (ClassLoader)null) && !ClassUtils.isPresent("org.glassfish.jersey.servlet.ServletContainer", (ClassLoader)null)) {
return REACTIVE;
} else {
String[] var0 = SERVLET_INDICATOR_CLASSES;
int var1 = var0.length;
for(int var2 = 0; var2 < var1; ++var2) {
String className = var0[var2];
if (!ClassUtils.isPresent(className, (ClassLoader)null)) {
return NONE;
}
}
return SERVLET;
}
}
以此推断类型
WebApplicationType.NONE #### 非web应用
WebApplicationType.SERVLET ### web REACTIVE
WebApplicationType.REACTIVE ### web SERVLET
3、推断引导类
在运行期线程堆栈中进行判断
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;
}
4、加载应用上下文初始器
通过加载jar包或者自配置的META-INF/spring.factories中进行初始化配置,可通过Order来控制其先后
org.springframework.context.ApplicationContextInitializer=\
com.springboot.diveinspringboot.context.LastApplicationContextInitializer,\
com.springboot.diveinspringboot.context.FirstApplicationContextInitializer
@Order(Ordered.HIGHEST_PRECEDENCE)
public class FirstApplicationContextInitializer<C extends ConfigurableApplicationContext> implements ApplicationContextInitializer<C> {
@Override
public void initialize(C c) {
System.out.println("I'm First");
}
}
public class LastApplicationContextInitializer implements ApplicationContextInitializer,Ordered {
@Override
public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
System.out.println("I'm Last");
}
@Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE;
}
}
但此时不能调用JavaBean因为此时还未初始化。
5、SpringApplication运行监听器
public class EventRunListener implements SpringApplicationRunListener {
/**
*
*/
public EventRunListener(SpringApplication application, String[] args) {
}
//Spring应用启动 监听事件-> ApplicationStartingEvent
@Override
public void starting() {
System.out.println("Spring starting : " + System.currentTimeMillis());
}
//ConfigurableEnvironment准备妥当,允许将其调整 监听事件-> ApplicationEnvironmentPreparedEvent
@Override
public void environmentPrepared(ConfigurableEnvironment environment) {
System.out.println("Spring environmentPrepared : " + System.currentTimeMillis());
}
//ConfigurableApplicationContext准备妥当,允许将其调整
@Override
public void contextPrepared(ConfigurableApplicationContext context) {
System.out.println("Spring contextPrepared : " + System.currentTimeMillis());
}
//ConfigurableApplicationContext已装载,但未启动 监听事件->ApplicationPreparedEvent
@Override
public void contextLoaded(ConfigurableApplicationContext context) {
System.out.println("Spring contextLoaded : " + System.currentTimeMillis());
}
//ConfigurableApplicationContext已启动,此时SpringBean初始化完成 监听事件->ApplicationStartedEvent
@Override
public void started(ConfigurableApplicationContext context) {
System.out.println("Spring started : " + System.currentTimeMillis());
}
//Spring正在运行 监听事件->ApplicationReadyEvent
@Override
public void running(ConfigurableApplicationContext context) {
System.out.println("Spring running : " + System.currentTimeMillis());
}
//Spring运行失败 监听事件->ApplicationFailedEvent
@Override
public void failed(ConfigurableApplicationContext context, Throwable exception) {
System.out.println("Spring failed : " + System.currentTimeMillis());
}
}
总结
spring应用启动包含错综复杂的阶段,其中推断web应用类型以及推断引导类决定了产生了不同的应用上下文和Environment,而应用上下文是通过读取spring.factories文件中组件以及spring framework本身的spring.factories文件中的组件来进行装载,装载存在先后顺序,以Ordered设置为基础,从高到低依次执行(级别数值越低,优先级越高)。在启动应用上下文时,同时会运行监听器,针对每个事件进行监听,如下:
# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.ClearCachesApplicationListener,\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
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