前言
此系列是针对springboot的启动,旨在于和大家一起来看看springboot启动的过程中到底做了一些什么事。文中有不清楚或错误的地方
欢迎留言指正。
源码解读进度
首先我们的源码阅读进度
public ConfigurableApplicationContext run(String... args) {
// 用于记录启动时间
StopWatch stopWatch = new StopWatch();
stopWatch.start();
// 声明Spring上下文
ConfigurableApplicationContext context = null;
// 声明启动错误回掉
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
// 设置jdk系统属性java.awt.headless,默认情况为true即开启
configureHeadlessProperty();
// 装饰者模式创建启动监听器(EventPublishingRunListener实例)
SpringApplicationRunListeners listeners = getRunListeners(args);
// 触发ApplicationStartingEvent事件,包括转换器的初始化
listeners.starting();
try {
// 参数封装,也就是在命令行下启动应用带的参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 准备环境:1、加载外部化配置的资源到environment;2、触发ApplicationEnvironmentPreparedEvent事件
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
// 1. 配置spring.beaninfo.ignore,并添加到名叫systemProperties的PropertySource中;默认为true即开启
configureIgnoreBeanInfo(environment);
// 2. 打印banner图
Banner printedBanner = printBanner(environment);
// 3. 创建应用上下文,这是本文重点
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;
}
1. configureIgnoreBeanInfo
看一下该方法的代码
private void configureIgnoreBeanInfo(ConfigurableEnvironment environment) {
if (System.getProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME) == null) {
Boolean ignore = environment.getProperty("spring.beaninfo.ignore", Boolean.class, Boolean.TRUE);
System.setProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME, ignore.toString());
}
}
配置spring.beaninfo.ignore,并添加到名叫systemProperties的PropertySource中,默认为true即开启,
如上图所示。至于spring.beaninfo.ignore配置这个有什么用,暂时不清楚。
2. printBanner
private Banner printBanner(ConfigurableEnvironment environment) {
if (this.bannerMode == Banner.Mode.OFF) {
return null;
}
ResourceLoader resourceLoader = (this.resourceLoader != null) ? this.resourceLoader
: new DefaultResourceLoader(getClassLoader());
SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(resourceLoader, this.banner);
if (this.bannerMode == Mode.LOG) {
return bannerPrinter.print(environment, this.mainApplicationClass, logger);
}
return bannerPrinter.print(environment, this.mainApplicationClass, System.out);
}
打印banner图,如下

并返回Banner对象,后面会用到
3. createApplicationContext本文重点
- 先看代码
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
switch (this.webApplicationType) {
case SERVLET:
contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
break;
case REACTIVE:
contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
break;
default:
contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
}
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex);
}
}
return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}
通过webApplicationType判断创建什么类型的Context,如果是SERVLET那么实例化
AnnotationConfigServletWebServerApplicationContext,利用反射调用无参构造器进行实例化。
-
下面看一下AnnotationConfigServletWebServerApplicationContext的类图
20200526182902487_15759.png
打眼一看继承关系很复杂,所以不要试图直接理清他们的关系。我们从具体的类单个分析,分析完之后会感觉就会感觉清晰了。
- EnvironmentCapable 接口表示一个组件包含并且暴露一个Environment引用,ApplicationContext继承了EnvironmentCapable,因此暴露了getEnvironment()方法; 然而,ConfigurableApplicationContext 重新定义了getEnvironment()方法,返回ConfigurableEnvironment既而缩小了方法签名。影响就是Environment对象是只读的直到其从ConfigurableApplicationContext中获得,在此时它可以被配制。
public interface EnvironmentCapable {
Environment getEnvironment();
}
- MessageSource 用于解析消息的策略接口,支持此类消息的参数化和国际化, 提供了三个方法
public interface MessageSource {
@Nullable
String getMessage(String code, @Nullable Object[] args, @Nullable String defaultMessage, Locale locale);
String getMessage(String code, @Nullable Object[] args, Locale locale) throws NoSuchMessageException;
String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException;
}
- ApplicationEventPublisher 封装事件发布功能的接口,提供了两个方法
@FunctionalInterface
public interface ApplicationEventPublisher {
default void publishEvent(ApplicationEvent event) {
publishEvent((Object) event);
}
void publishEvent(Object event);
}
- ResourcePatternResolver 解析为Resource对象的策略接口,实现类PathMatchingResourcePatternResolver
可以解析包括jar包里面的配置,也可以解析包含通配符的路径(*、?、{})
public interface ResourcePatternResolver extends ResourceLoader {
String CLASSPATH_ALL_URL_PREFIX = "classpath*:";
Resource[] getResources(String locationPattern) throws IOException;
}
- ResourceLoader提供 classpath下单资源文件的载入,实现类DefaultResourceLoader
public interface ResourceLoader {
String CLASSPATH_URL_PREFIX = ResourceUtils.CLASSPATH_URL_PREFIX;
Resource getResource(String location);
@Nullable
ClassLoader getClassLoader();
}
- BeanFactory 是一个Bean工厂方法接口,里面提供了一些对Bean操作的方法
- HierarchicalBeanFactory 声明了一个getParentBeanFactory方法
- ListableBeanFactory 里面声明了一些有关BeanDefinition的方法
再看一下AnnotationConfigServletWebServerApplicationContext的构造方法
public AnnotationConfigServletWebServerApplicationContext(DefaultListableBeanFactory beanFactory) {
super(beanFactory);
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
- AbstractApplicationContext,抽象应用上下文。初始化属性resourcePatternResolver,也就是资源模式解析器;实际类型是PathMatchingResourcePatternResolver
- GenericApplicationContext,通用应用上下文。初始化属性beanFactory,其类型是DefaultListableBeanFactory
- GenericWebApplicationContext,通用web应用上下文,在GenericApplicationContext基础上增加web支持
- ServletWebServerApplicationContext,servlet web服务应用上下文,能够从自身引导,创建,初始化和运行WebServer
通过这些接口,可以了解到ApplicationContext的基本功能
- 看一下AnnotationConfigServletWebServerApplicationContext通过构造方法,
public AnnotationConfigServletWebServerApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
可以看到初始化了AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner用于BeanDefinition注册
父类GenericApplicationContext的构造器中初始化了beanFactory,beanFactory的实现是DefaultListableBeanFactory。
网友评论