本文基于springboot 2.1.3版本进行解析。
Spring Boot 的入口类
@SpringBootApplication
public class SpringbootSecurityApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootSecurityApplication.class, args);
}
}
如上是最简单的springboot的入口类
@SpringBootApplication注解启动spring boot特性,通过run方法来启动spring boot项目
public static ConfigurableApplicationContext run(Class<?>[] primarySources,
String[] args) {
return new SpringApplication(primarySources).run(args);
}
可以看到用primarySources实例化SpringApplication对象。再调用实例的run方法来进行启动。
SpringApplication的实例化
public SpringApplication(Class<?>... primarySources) {
this(null, primarySources);
}
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
// 1. 资源加载器初始化为null
this.resourceLoader = resourceLoader;
// 2 传入的primarySources类不能为空
Assert.notNull(primarySources, "PrimarySources must not be null");
// 3 传入的primarySources去重
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 4 根据类的路径判断当前 WEB 应用类型
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 5 设置上下文初始类
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
// 6 设置监听
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
//7 主入口应用类
this.mainApplicationClass = deduceMainApplicationClass();
}
实例化的过程,写在代码的注释中。
ApplicationContextInitializer 是什么?
用来初始化指定的 Spring 应用上下文,如注册属性资源、激活 Profiles 等。
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
public void setInitializers(
Collection<? extends ApplicationContextInitializer<?>> initializers) {
this.initializers = new ArrayList<>();
this.initializers.addAll(initializers);
}
setInitializers 方法比较简单,初始化一个集合,并将ApplicationContextInitializer的初始化类加入集合
如何通过工厂类获取所有的初始化类实例?
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = getClassLoader();
// Use names and ensure unique to protect against duplicates
Set<String> names = new LinkedHashSet<>(
SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
- 获取当前的classLoader
public ClassLoader getClassLoader() {
if (this.resourceLoader != null) {
return this.resourceLoader.getClassLoader();
}
return ClassUtils.getDefaultClassLoader();
}
resourceLoader 当前设置为null,类加载器为默认的类加载器;默认的类加载器,是当前线程的类加载器
-
获取
ApplicationContextInitializer
的实例名称集合并去重根据类路径下的META-INF/spring.factories文件解析获取ApplicationContextInitializer接口的所有配置类路径名称
文件的内容如下:# 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.web.context.ServerPortInfoApplicationContextInitializer
-
根据类路径创建初始化器实例列表
-
初始化器实例列表排序
-
返回初始化器实例列表
ApplicationListener 监听器
监听器是用来处理application 时间的。它继承了EventListener和ApplicationEvent。
@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
/**
* Handle an application event.
* @param event the event to respond to
*/
void onApplicationEvent(E event);
}
public void setListeners(Collection<? extends ApplicationListener<?>> listeners) {
this.listeners = new ArrayList<>();
this.listeners.addAll(listeners);
}
监听器的设置同ApplicationContextInitializer 一样,也是通过加载META-INF/spring.factories文件中的监听器instances,最终放入集合中
获取主入口应用类
创建一个运行时异常栈,遍历异常栈中的方法名;如果存在main的方法,则返回类,即为入口应用类的名字
private Class<?> deduceMainApplicationClass() {
try {
StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
for (StackTraceElement stackTraceElement : stackTrace) {
if ("main".equals(stackTraceElement.getMethodName())) {
return Class.forName(stackTraceElement.getClassName());
}
}
}
catch (ClassNotFoundException ex) {
// Swallow and continue
}
return null;
}