SpringBoot启动过程
@SpringBootApplication
public class MySpringApplication {
public static void main(String[] args) {
ApplicationContext applicationContext = SpringApplication.run(MySpringApplication.class, args);
}
}
SpringBoot工程的启动都是通过SpringApplication.run()方法启动的,包括SpringApplication构造的调用和run()方法的运行。
SpringApplication的构造过程
1.SpringApplication中有段静态代码块:
static {
Set<String> names = new HashSet<String>();
// public static final String SERVLET_CONTEXT_PROPERTY_SOURCE_NAME = "servletContextInitParams";
// public static final String SERVLET_CONFIG_PROPERTY_SOURCE_NAME = "servletConfigInitParams";
// public static final String JNDI_PROPERTY_SOURCE_NAME = "jndiProperties";
names.add(StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME);
names.add(StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME);
names.add(StandardServletEnvironment.JNDI_PROPERTY_SOURCE_NAME);
// 将上面三个servlet属性值设置到集合中,unmodifiableSet()方法返回的集合是不可修改的
SERVLET_ENVIRONMENT_SOURCE_NAMES = Collections.unmodifiableSet(names);
}
2.再初始化logger属性:
private static final Log logger = LogFactory.getLog(SpringApplication.class);
3.执行initialize()方法(有一个重构方法,暂时忽略):
public SpringApplication(Object... sources) {
initialize(sources);
}
4.initialize()方法执行过程:
// 抑制一下两种告警
@SuppressWarnings({ "unchecked", "rawtypes" })
private void initialize(Object[] sources) {
if (sources != null && sources.length > 0) {
// private final Set<Object> sources = new LinkedHashSet<Object>();
// sources属性是一个Set,也就是将MySpringApplication.class存入sources
this.sources.addAll(Arrays.asList(sources));
}
// 判断是否时web环境
this.webEnvironment = deduceWebEnvironment();
// private List<ApplicationContextInitializer<?>> initializers;
// 将ApplicationContextInitializer类型的初始化器实例化后存入initializers
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
// private List<ApplicationListener<?>> listeners;
// 将ApplicationListener类型的监听器实例化后存入listeners
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 找到有main()方法的类(就是也就是将MySpringApplication)存入mainApplicationClass
this.mainApplicationClass = deduceMainApplicationClass();
}
补充:
-
ApplicationContextInitializer,应用程序初始化器,做一些初始化的工作,也可以通过实现ApplicationContextInitializer接口来自定义初始化器;
-
ApplicationListener,应用程序事件(ApplicationEvent)监听器,SpringBoot提供的监听事件有5个:ApplicationStartedEvent、ApplicationEnvironmentPreparedEvent、ApplicationPreparedEvent、ApplicationReadyEvent、ApplicationFailedEvent。自定义监听器大致分为三个步骤:
1.自定义事件:继承自ApplicationEvent抽象类,然后定义自己的构造器;
2.自定义监听器:实现ApplicationListener接口,然后实现onApplicationEvent方法;
3.将监听器通过addApplicationListener()注册到Spring应用上下文(ConfigurableApplicationContext);
5.setInitializers()和setListeners()都是调用了getSpringFactoriesInstances()方法:
private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type) {
return getSpringFactoriesInstances(type, new Class<?>[] {});
}
// 实际调用的getSpringFactoriesInstances():
private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, Object... args) {
// 获取线程的classLoader
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
// loadFactoryNames()从默认路径"META-INF/spring.factories"中获取符合type的所有类名全称,并将名字返回一个set集合
Set<String> names = new LinkedHashSet<String>(
SpringFactoriesLoader.loadFactoryNames(type, classLoader));
// createSpringFactoriesInstances()中通过ClassUtils.forName(name, classLoader)方法将所有类实例化返回List
List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
classLoader, args, names);
// 将返回的instances根据配置排序,如@Order(1),因为其继承了OrderComparator类,该类实现了compare()方法,实际时调用了doCompare()方法,实现了通过@Order注解来排序
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
SpringApplication run()方法的执行过程
run()方法源码:
public ConfigurableApplicationContext run(String... args) {
// 实例化一个监视器stopWatch,主要是记录时间和避免重复调用run()方法
StopWatch stopWatch = new StopWatch();
// 启动stopWatch,将状态设置为this.running = true;
stopWatch.start();
// 创建context,先设为null
ConfigurableApplicationContext context = null;
// Headless模式是在缺少显示屏、键盘或者鼠标时的系统配置,this.headless属性默认为true,该方法就是配置该属性
configureHeadlessProperty();
// SpringApplicationRunListeners包含log和SpringApplicationRunListener列表两个属性,并继承SpringApplicationRunListener接口包含5个方法:
// void started();
// void environmentPrepared(ConfigurableEnvironment environment);
// void contextPrepared(ConfigurableApplicationContext context);
// void contextLoaded(ConfigurableApplicationContext context);
// void finished(ConfigurableApplicationContext context, Throwable exception);
// 这5个接口方法在SpringApplicationRunListeners类中实现,每个方法都循环通知所有监听器,也即所说的广播
SpringApplicationRunListeners listeners = getRunListeners(args);
// 设置了ApplicationStartedEvent事件的监听器会收到事件并执行配置的逻辑
listeners.started();
try {
// 实例化应用参数类
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
// 创建并根据启动时传入的参数更新context
context = createAndRefreshContext(listeners, applicationArguments);
// 看下面的afterRefresh源码
afterRefresh(context, applicationArguments);
// 广播ApplicationReadyEvent事件,exception参数为null,所以是ApplicationReadyEvent事件
listeners.finished(context, null);
// 停止stopWatch,会计算出启动耗时
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
return context;
}
catch (Throwable ex) {
// 会广播ApplicationFailedEvent事件
handleRunFailure(context, listeners, ex);
throw new IllegalStateException(ex);
}
}
createAndRefreshContext()方法源码:
private ConfigurableApplicationContext createAndRefreshContext(
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
ConfigurableApplicationContext context;
// 创建并配置环境变量,如果可以get则get,get为null就创建一个
ConfigurableEnvironment environment = getOrCreateEnvironment();
// 将args(启动时的参数)设置到environment中
configureEnvironment(environment, applicationArguments.getSourceArgs());
// 通知监听器,ApplicationEnvironmentPreparedEvent事件
listeners.environmentPrepared(environment);
// 如果不是web环境就跳过if
if (isWebEnvironment(environment) && !this.webEnvironment) {
environment = convertToStandardEnvironment(environment);
}
// 输出Spring图形启动画面
if (this.bannerMode != Banner.Mode.OFF) {
printBanner(environment);
}
// Create, load, refresh and run the ApplicationContext
// 创建context
context = createApplicationContext();
// 设置context的environment
context.setEnvironment(environment);
// 向context注册beanNameGenerator、resourceLoader、ClassLoader
postProcessApplicationContext(context);
// 应用Initializers初始化器
applyInitializers(context);
// EventPublishingRunListener发布contextPrepare事件,因为此事件为空,所以此次未做任何操作。
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// 把applicationArguments注册到context中,且为单例模式
context.getBeanFactory().registerSingleton("springApplicationArguments",
applicationArguments);
// 加载sources
Set<Object> sources = getSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[sources.size()]));
// 发布ApplicationPreparedEvent事件给各个监听器
listeners.contextLoaded(context);
// 刷新Spring应用上下文
refresh(context);
if (this.registerShutdownHook) {
try {
// 注册钩子,避免程序异常关闭资源不释放
context.registerShutdownHook();
}
catch (AccessControlException ex) {
// Not allowed in some environments.
}
}
return context;
}
createApplicationContext()方法源码:
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
// 如果是web环境,将org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext实例化给contextClass
// 如果不是,将org.springframework.context.annotation.AnnotationConfigApplicationContext实例化给contextClass
contextClass = Class.forName(this.webEnvironment
? DEFAULT_WEB_CONTEXT_CLASS : DEFAULT_CONTEXT_CLASS);
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Unable create a default ApplicationContext, "
+ "please specify an ApplicationContextClass",
ex);
}
}
return (ConfigurableApplicationContext) BeanUtils.instantiate(contextClass);
}
postProcessApplicationContext()方法源码:
protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
if (this.webEnvironment) {
if (context instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext configurableContext = (ConfigurableWebApplicationContext) context;
if (this.beanNameGenerator != null) {
// 向context的BeanFactory中注册了beanNameGenerator
configurableContext.getBeanFactory().registerSingleton(
AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
this.beanNameGenerator);
}
}
}
// 如果SpringApplication设置了资源加载器
if (this.resourceLoader != null) {
if (context instanceof GenericApplicationContext) {
// 向context中set了resourceLoader
((GenericApplicationContext) context)
.setResourceLoader(this.resourceLoader);
}
if (context instanceof DefaultResourceLoader) {
// 向context中set了ClassLoader
((DefaultResourceLoader) context)
.setClassLoader(this.resourceLoader.getClassLoader());
}
}
}
applyInitializers()方法源码:
protected void applyInitializers(ConfigurableApplicationContext context) {
// 获取所有的initializer,
for (ApplicationContextInitializer initializer : getInitializers()) {
Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(
initializer.getClass(), ApplicationContextInitializer.class);
Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
// 不同的初始化器执行各自的initialize()方法执行初始化操作
initializer.initialize(context);
}
}
getInitializers()方法源码:
public Set<ApplicationContextInitializer<?>> getInitializers() {
// 返回不可更改的initializers集合
return asUnmodifiableOrderedSet(this.initializers);
}
afterRefresh()方法源码:
protected void afterRefresh(ConfigurableApplicationContext context,
ApplicationArguments args) {
// 空的,没执行任何操作
afterRefresh(context, args.getSourceArgs());
// 调用所有的Runner
callRunners(context, args);
}
callRunners()方法源码:
private void callRunners(ApplicationContext context, ApplicationArguments args) {
List<Object> runners = new ArrayList<Object>();
// 将所有的ApplicationRunner和CommandLineRunner都添加到runners中
runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
// 根据Order接口实现的排序规则排序
AnnotationAwareOrderComparator.sort(runners);
// 根据不通的runner类型调用不通的callRunner方法,callRunner方法有两个实现
for (Object runner : new LinkedHashSet<Object>(runners)) {
if (runner instanceof ApplicationRunner) {
callRunner((ApplicationRunner) runner, args);
}
if (runner instanceof CommandLineRunner) {
callRunner((CommandLineRunner) runner, args);
}
}
}
575

被折叠的 条评论
为什么被折叠?



