目录
1. 一个springboot程序的简单启动
如果我们想要启动一个springboot程序,只需要以下两步。
- pom文件引入相关依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.3.4.RELEASE</version>
</dependency>
- 编写启动类
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication application = new SpringApplication(App.class);
application.run(args);
//或者用下面这一行代码,跟上面两行代码的作用是一样的。
//SpringApplication.run(App.class, args);
}
}
2. new SpringApplication(App.class)
中发生了什么?
- resourceLoader ,这是spring加载资源的统一入口。后续专题讲解。
- primarySources,此处会对主配置源参数做初始化,后续注册到容器时会用到。后续专题讲解。
- 判断并设置启动类型:现有NONE、SERVLET、REACTIVE三种,我们这里是SERVLET
- 寻找
ApplicationContextInitializer
的配置并实例化。 - 寻找
ApplicationListener
的配置并实例化。 - 获取启动类。也就是启动main方法的那个类。
......
//构造方法会初始化一下5个属性的值。
private ResourceLoader resourceLoader;
private Set<Class<?>> primarySources;
private List<ApplicationContextInitializer<?>> initializers;
private Class<?> mainApplicationClass;
private List<ApplicationListener<?>> listeners;
......
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
//resourceLoader 是做什么的,后续专题分析。总的来说就是spring框架用来加载资源的一套接口。
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources `= new LinkedHashSet<>(Arrays.asList(primarySources));
//判断启动类型(NONE、SERVLET、REACTIVE三种)
this.webApplicationType = WebApplicationType.deduceFromClasspath();
//从META-INF/spring.factories文件获取对应ApplicationContextInitializer的配置,并实例化。
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
//从META-INF/spring.factories文件获取对应ApplicationListener的配置,并实例化。
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
//获取启动类。也就是启动main方法的那个类。
this.mainApplicationClass = deduceMainApplicationClass();
}
2.1 getSpringFactoriesInstances()
方法解析
这个方法或根据入参,在META-INF/spring.factories文件中找到相应类的配置,实例化相应对象并返回。具体可以自己去看源码。
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;
}
2.2 ApplicationContextInitializer
和ApplicationListener
是什么?
从上文,我们知道启动是以上相应的实例到SpringApplication
对象中,那么这里到底实例化了哪些对象,又各有什么作用。默认实例化了一下7个ApplicationContextInitializer
和11个ApplicationListener
对象,具体作用,后续用到在进行详解。下面我们开始分析 ApplicationContextInitializer
和ApplicationListener
两个接口。
2.2.1 ApplicationContextInitializer
接口详解
这个接口的官方解释大致如下:
- 用于在spring容器刷新之前初始化Spring ConfigurableApplicationContext的回调接口。(剪短说就是在容器刷新之前调用该类的 initialize 方法。并将 ConfigurableApplicationContext 类的实例传递给该方法)
- 通常用于需要对应用程序上下文进行编程初始化的web应用程序中。例如,根据上下文环境注册属性源或激活配置文件等。
- 可排序的(实现Ordered接口,或者添加@Order注解)
总的来说,就是在spring容器刷新前,对传入的容器applicationContext进行一些初始化的操作,具体的调用位置后面再说。
public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> {
/**
* Initialize the given application context.
* @param applicationContext the application to configure
*/
void initialize(C applicationContext);
}
2.2.2 ApplicationListener
接口详解
一看就是spring的观察者(监听器)模式。上面注册的11个监听器会在对应事件发出时回调 onApplicationEvent(E event)
方法。
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
/**
* Handle an application event.
* @param event the event to respond to
*/
void onApplicationEvent(E event);
}
3.application.run(args)
-springboot启动最重要的方法
application.run(args)
方法是springboot启动过程中最重要的方法,在下一篇中进行详细介绍。
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
//从META-INF/spring.factories文件获取对应SpringApplicationRunListener的配置,并实例化,放入SpringApplicationRunListeners 的List<SpringApplicationRunListener> listeners属性中。
SpringApplicationRunListeners listeners = getRunListeners(args);
//里面会调用每个SpringApplicationRunListener的starting()方法,SpringApplicationRunListener类的具体作用,下文再进行介绍。
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//环境准备
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
listeners.started(context);
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}