public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");//主程序入口不能为空
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));//主程序入口是可以为多个的,也就是说可以配置多个,根据不同的环境启动不同的程序入口
this.webApplicationType = WebApplicationType.deduceFromClasspath();//确定程序的类型,见下文
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
deduceFromClasspath()
private static final String[] SERVLET_INDICATOR_CLASSES = { "javax.servlet.Servlet",
"org.springframework.web.context.ConfigurableWebApplicationContext" };
private static final String WEBMVC_INDICATOR_CLASS = "org.springframework.web.servlet.DispatcherServlet";
private static final String WEBFLUX_INDICATOR_CLASS = "org.springframework.web.reactive.DispatcherHandler";
private static final String JERSEY_INDICATOR_CLASS = "org.glassfish.jersey.servlet.ServletContainer";
private static final String SERVLET_APPLICATION_CONTEXT_CLASS = "org.springframework.web.context.WebApplicationContext";
private static final String REACTIVE_APPLICATION_CONTEXT_CLASS = "org.springframework.boot.web.reactive.context.ReactiveWebApplicationContext";
static WebApplicationType deduceFromClasspath() {
if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
return WebApplicationType.REACTIVE;
}
for (String className : SERVLET_INDICATOR_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE;
}
}
return WebApplicationType.SERVLET;
}
org.springframework.boot.WebApplicationType WEB应用程序的类型有三种
- NONE
- Servlet
- Reactive
三种情况。
ClassUtils.isPresent(String className, @Nullable ClassLoader classLoader)方法的作用:通过检查类的全限定名称,看对应类是否存在。
上面的代码也就是对tomcat和glassfish还有reactive 进行了判断。判断的过程,如果reactive存在,而其他两种都不存在,则认为当前的这个web程序是reactive ,如果SERVLET_INDICATOR_CLASSES 内的类其中一个不存在判断为都不是,如果上述条件都不满足,也就是SERVLET_INDICATOR_CLASSES存在同时 reactive不存在的情况下,成为被判断为是SERVLET程序。
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
该方法是获取实现了ApplicationContextInitializer接口的工厂类实例,这些工程类的实例的列表都存储在了META-INF/spring.factories文件中,或者运行环境下的META-INF/spring.factories中,通过classLoader获取的所有jar和classpath下的对应文件,文件中包含的内容清单如下,每一个工厂类都通过键值对的形式,等号前面是接口,后面是实现类的集合,通过用逗号隔开。例如以下的应用上下文的实现类。在这个地方仅仅只是将所有的工厂类的进行了收集还没有初始化。需要初始化就需要调用方法initialize。后面的获取监听器的方法也是一样的。
# springboot.jar中的
# 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.rsocket.context.RSocketPortInfoApplicationContextInitializer,\
org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer
#springboot-autoconfiguration中的
# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
ApplicationListener
这个接口的作用是当应用有对应的事件时进行处理。该接口在实现时需要同时实现一个ApplicationEvent接口来定义事件。
程序一直运行到这里的时候还没有初始化服务 this.mainApplicationClass = deduceMainApplicationClass();这里仅仅是通过运行方法栈堆,找到当前运行线程中main方法定义的类。
接下来着重看一下 public ConfigurableApplicationContext org.springframework.boot.SpringApplication.run(String… args) 方法。代码块看起来还是非常的清晰的。
public ConfigurableApplicationContext run(String... args) {
//首先定义了一个计时器,记录了系统从初始化前到初始化结束所用的时间
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();//针对awt设置的headless
SpringApplicationRunListeners listeners = getRunListeners(args);//初始化了一个时间监听器
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();//根据应用类型初始化自动配置的上下文类型,AnnotationConfigServletWebServerApplicationContext是servlet的通过注解自动配置的初始化应用上下文
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;
}
准备工作
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
context.setEnvironment(environment);
postProcessApplicationContext(context);
applyInitializers(context);//真正初始化调用类的方法的时候
listeners.contextPrepared(context);//监听器的初始化
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
//系统默认懒加载是不开启的
if (this.lazyInitialization) {
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
// Load the sources
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[0]));//初始化Bean对象定义的工厂类,配置环境,配置资源加载器
listeners.contextLoaded(context);//SpringApplicationRunListener加载
}
springboot为我们提供了一个启动应用程序的框架,通过工厂类和监听器的定义,我们可以将应用制作成一个个插件,就可以无缝的移植进入。