有两大步:①创建spring应用 ②把spring应用跑起来
一、创建SpringApplication
@SpringBootApplication
public class Boot09HelloTestApplication {
public static void main(String[] args) {
SpringApplication.run(Boot09HelloTestApplication.class, args);
}
}
step into
使用new class把主程序类传进来,然后调用run方法
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return run(new Class[]{primarySource}, args);
}
step into run方法
第一步,创建spring应用。第二步把spring应用跑起来
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return (new SpringApplication(primarySources)).run(args);
}
step into 看看创建spring应用的过程是怎么的
public SpringApplication(Class... primarySources) {
//调用本类有参构造器,传入两个参数
this((ResourceLoader)null, primarySources);
}
step into this方法
初始化了好多属性
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
//第一个属性,资源加载器resourceLoader
this.resourceLoader = resourceLoader;
//断言你有主配置类,如果没有,则报错
Assert.notNull(primarySources, "PrimarySources must not be null");
//把主配置类信息保存起来,
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
//决定当前web应用的类型。如何决定的看下面的源码
this.webApplicationType = WebApplicationType.deduceFromClasspath();
//bootstrappers:初始启动引导器(项目一启动就要干什么)。如何获取的看下面的源码
this.bootstrappers = new ArrayList<>(getSpringFactoriesInstances(Bootstrapper.class));
//设置初始化器。只要看到getSpringFactoriesInstances这个方法,都是去META-INF/spring.factories文件中有没有配置某个类类,它的值是什么
//如果找到了ApplicationContextInitializer,就会放到List<ApplicationContextInitializer<?>> initializers里
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
//设置监听器。去spring.factories文件中有没有配置ApplicationListener类,它的值是什么
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
//找主程序。决定哪个是主程序。如何决定的看下面的源码分析
this.mainApplicationClass = deduceMainApplicationClass();
}
如何决定当前web应用的类型??Servlet or 响应式编程?
static WebApplicationType deduceFromClasspath() {
//使用ClassUtils工具类判断当前系统有没有导入org.springframework.web.reactive.DispatcherHandler响应式编程的请求处理器
if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
//如果是响应式编程,相当于导入了DispatcherHandler类,就会返回它是一个响应式编程
return WebApplicationType.REACTIVE;
}
//如果是原生的serlvet编程
for (String className : SERVLET_INDICATOR_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE;
}
}
//如果是原生的serlvet编程,就会返回它是一个原生的serlvet编程
return WebApplicationType.SERVLET;
}
如何获取初始化启动器??
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
return getSpringFactoriesInstances(type, new Class<?>[] {});
}
//进入getSpringFactoriesInstances方法
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
//获取类的加载器
ClassLoader classLoader = getClassLoader();
//spring.factories文件中找类型是org.springframework.boot.Bootstrapper
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
//如果没找到,即没人配置它。如果有,就会创建实例并返回
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
如何决定哪个是主程序???
private Class<?> deduceMainApplicationClass() {
try {
//去堆栈里找哪个类是有main方法的,有main方法的就是主程序,主程序有很多,只有找到第一个有main方法的就行了
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;
}
创建SpringApplication小总结
保存一些信息。
判定当前应用的类型。Servlet or 响应式编程
bootstrappers:初始启动引导器(List<Bootstrapper>):去spring.factories文件中找org.springframework.boot.Bootstrapper
找ApplicationContextInitializer;去spring.factories找 ApplicationContextInitializer,保存在 List<ApplicationContextInitializer<?>> initializers
找ApplicationListener应用监听器。去spring.factories找ApplicationListener,保存在List<ApplicationListener<?>> listeners
简单来说,应用创建的过程,就是把一些关键的主键去spring.factories文件中给我们把信息读取出来,提前保存到springapplication里
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。