目录
1.生成一个SpringApplication的实例new SpringApplication(Sources)
2.运行SpringApplication的实例进行初始化操作
2.1.3.创建SpringApplicationRunListeners,发送广播
2.1.4.配置环境模块ConfigurableEnvironment
2.1.6.ConfigurableApplicationContext spring容器
debug调式SpringBoot 1.5.8的源码,运行在tomcat上。
Spring Boot 通过扫描classpath下的实例决定装载哪个web容器。
我这里pom.xml文件用的spring-boot-starter-web所以,会启动tomcat来作为servlet的容器。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
流程图:
顺序是从左往后,左边全部完了才执行右边的。
入口:启动类
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
进入SpringApplication中可以看到run方法做了两件事
public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
return new SpringApplication(sources).run(args);
}
1.生成一个SpringApplication的实例new SpringApplication(Sources)
SpringApplication的构造方法中调用了initialize方法
private void initialize(Object[] sources) {
//配置source
if (sources != null && sources.length > 0) {
this.sources.addAll(Arrays.asList(sources));
}
//配置是否为web环境
this.webEnvironment = deduceWebEnvironment();
//设置初始化器
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
//设置监听器
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
//配置应用的主方法所在类
this.mainApplicationClass = deduceMainApplicationClass();
}
1.1initialize方法主要做的事情有:
1.1.1.配置source
if (sources != null && sources.length > 0) {
this.sources.addAll(Arrays.asList(sources));
}
1.1.2.配置是否为web环境
this.webEnvironment = deduceWebEnvironment();
private boolean deduceWebEnvironment() {
for (String className : WEB_ENVIRONMENT_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return false;
}
}
return true;
}
1.1.3.创建并且设置初始化器
从spring.factories文件中创建所有的初始化器
setInitializers((Collection)getSpringFactoriesInstances(ApplicationContextInitializer.class));
通过断点可以看到有如下6种初始化器
org.springframework.boot.context.config.DelegatingApplicationContextInitializer
org.springframework.boot.context.ContextIdApplicationContextInitializer
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer
org.springframework.boot.context.embedded.ServerPortInfoApplicationContextInitializer
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer
org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer
这里详细讲一下怎么得到工厂类实例的
进入getSpringFactoriesInstances方法 :
获取传入的工厂类名、类加载器
private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, Object... args) {
//类加载器
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Set<String> names = new LinkedHashSet<String>(
//通过类加载器获取指定的spring.factories文件,获取文件中工厂类的全路径,得到工厂类名
SpringFactoriesLoader.loadFactoryNames(type, classLoader));
//通过类路径反射得到工厂的class对象、构造方法,生成工厂类实例返回
List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
SpringFactoriesLoader.loadFactoryNames方法:
通过类加载器获取指定的spring.factories文件,获取文件中工厂类的全路径,得到工厂类名
public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
try {
//通过类加载器获取指定的spring.factories文件
Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
List<String> result = new ArrayList<String>();
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
//获取文件中工厂类的全路径
String factoryClassNames = properties.getProperty(factoryClassName);
result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
}
return result;
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() +
"] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex);
}
}
createSpringFactoriesInstances方法:
通过类路径反射得到工厂的class对象、构造方法,生成工厂类实例返回
private <T> List<T> createSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args,
Set<String> names) {
List<T> instances = new ArrayList<T>(names.size());
for (String name : names) {
try {
//通过类路径反射得到工厂的class对象
Class<?> instanceClass = ClassUtils.forName(name, classLoader);
Assert.isAssignable(type, instanceClass);
//得到构造方法
Constructor<?> constructor = instanceClass
.getDeclaredConstructor(parameterTypes);
//得到实例
T instance = (T) BeanUtils.instantiateClass(constructor, args);
instances.add(instance);
}
catch (Throwable ex) {
throw new IllegalArgumentException(
"Cannot instantiate " + type + " : " + name, ex);
}
}
return instances;
}
1.1.4.创建并且设置监听器
从spring.factories文件中创建应用监听器
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
这里的getSpringFactoriesInstances方法跟上面创建设置初始化器一样,只是入参不一样,这里入参是ApplicationListener.class
通过断点可以看到有如下10种监听器
org.springframework.boot.ClearCachesApplicationListener
org.springframework.boot.builder.ParentContextCloserApplicationListener
org.springframework.boot.context.FileEncodingApplicationListener
org.springframework.boot.context.config.AnsiOutputApplicationListener
org.springframework.boot.context.config.ConfigFileApplicationListener
org.springframework.boot.context.config.DelegatingApplicationListener
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener
org.springframework.boot.logging.ClasspathLoggingApplicationListener
org.springframework.boot.logging.LoggingApplicationListener
org.springframework.boot.autoconfigure.BackgroundPreinitializer
其中
ConfigFileApplicationListener监听器的核心作用就是读取application.yml配置文件内容
1.1.5.配置应用的主方法所在类
this.mainApplicationClass = deduceMainApplicationClass();
private Class<?> deduceMainApplicationClass() {
try {
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;
}
2.运行SpringApplication的实例进行初始化操作
SpringApplication的实例创建好后调用run方法
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
//开始计时(初始化需要花费多少时间)
stopWatch.start();
ConfigurableApplicationContext context = null;
FailureAnalyzers analyzers = null;
//配置headless
configureHeadlessProperty();
//实现类只有EventPublishingRunListener
//通过SpringApplicationRunListeners广播
SpringApplicationRunListeners listeners = getRunListeners(args);
//收到广播的类执行相应的操作
listeners.starting();
try {
//// 构造一个应用程序参数持有类
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
// 配置环境模块
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
//配置Banner
Banner printedBanner = printBanner(environment);
// 创建Spring容器
context = createApplicationContext();
analyzers = new FailureAnalyzers(context);
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
// 广播出ApplicationReadyEvent事件给相应的监听器执行
listeners.finished(context, null);
//计时结束
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
return context;
}
catch (Throwable ex) {
handleRunFailure(context, listeners, analyzers, ex);
throw new IllegalStateException(ex);
}
}
2.1run方法主要做的事有:
2.1.1.stopWatch.start()
开始计时初始化需要花费多少时间
2.1.2.Headless配置
configureHeadlessProperty();
private void configureHeadlessProperty() {
System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, System.getProperty(
SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless)));
}
2.1.3.创建SpringApplicationRunListeners,发送广播
SpringApplicationRunListener目前只有一个实现类EventPublishingRunListener
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
SpringApplicationRunListener.class, types, this, args));
}
SpringApplicationRunListenesr类有5个方法,这五个方法调用的时间不同,发送了不同的事件
方法 | 何时调用 | 对应事件 |
|
run方法执行时就调用 | ApplicationStartedEvent |
|
ApplicationContext创建之前并且环境信息准备好的时候调用 | ApplicationEnvironmentPreparedEvent |
|
ApplicationContext创建好并且在source加载之前调用一次 | 无 |
|
ApplicationContext创建并加载之后并在refresh之前调用 | ApplicationPreparedEvent |
|
run方法结束之前调用 | ApplicationReadyEvent或ApplicationFailedEvent |
2.1.4.配置环境模块ConfigurableEnvironment
配置一些环境信息。
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
创建应用程序的环境信息。如果是web程序,创建StandardServletEnvironment;否则,创建StandardEnvironment。
配置一些环境信息。比如profile,命令行参数。
广播出ApplicationEnvironmentPreparedEvent事件给相应的监听器执行
环境信息的校对
private ConfigurableEnvironment prepareEnvironment(
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// 创建应用程序的环境信息。如果是web程序,创建StandardServletEnvironment;否则,创建StandardEnvironment
ConfigurableEnvironment environment = getOrCreateEnvironment();
// 配置一些环境信息。比如profile,命令行参数
configureEnvironment(environment, applicationArguments.getSourceArgs());
// 广播出ApplicationEnvironmentPreparedEvent事件给相应的监听器执行
listeners.environmentPrepared(environment);
// 环境信息的校对
if (!this.webEnvironment) {
environment = new EnvironmentConverter(getClassLoader())
.convertToStandardEnvironmentIfNecessary(environment);
}
return environment;
}
2.1.5.配置Banner
是否在控制台上打印自定义的banner
Banner printedBanner = printBanner(environment);
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);
}
2.1.6.ConfigurableApplicationContext spring容器
2.1.6.1创建spring容器
context = createApplicationContext();
如果是web程序,那么构造org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext容器 ,否则构造org.springframework.context.annotation.AnnotationConfigApplicationContext容器
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
// 如果是web程序,那么构造org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext容器
// 否则构造org.springframework.context.annotation.AnnotationConfigApplicationContext容器
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);
}
2.1.6.2配置spring容器
设置Spring容器的环境信息。
回调方法,Spring容器创建之后做一些额外的事。
SpringApplication的的初始化器开始工作。
遍历调用SpringApplicationRunListener的contextPrepared方法。目前只是将这个事件广播器注册到Spring容器中。
把应用程序参数持有类注册到Spring容器中,并且是一个单例。
广播出ApplicationPreparedEvent事件给相应的监听器执行
prepareContext(context, environment, listeners, applicationArguments,printedBanner);
private void prepareContext(ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
// 设置Spring容器的环境信息
context.setEnvironment(environment);
// 回调方法,Spring容器创建之后做一些额外的事
postProcessApplicationContext(context);
// SpringApplication的的初始化器开始工作
applyInitializers(context);
// 遍历调用SpringApplicationRunListener的contextPrepared方法。目前只是将这个事件广播器注册到Spring容器中
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// 把应用程序参数持有类注册到Spring容器中,并且是一个单例
context.getBeanFactory().registerSingleton("springApplicationArguments",
applicationArguments);
if (printedBanner != null) {
context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
}
// Load the 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);
}
2.1.6.3刷新spring容器
refreshContext(context);
private void refreshContext(ConfigurableApplicationContext context) {
refresh(context);
if (this.registerShutdownHook) {
try {
context.registerShutdownHook();
}
catch (AccessControlException ex) {
// Not allowed in some environments.
}
}
}
protected void refresh(ApplicationContext applicationContext) {
Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
((AbstractApplicationContext) applicationContext).refresh();
}
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
其中
prepareRefresh方法
- 设置Spring容器的启动时间,撤销关闭状态,开启活跃状态。
- 初始化属性源信息
- 验证环境信息里一些必须存在的属性
obtainFreshBeanFactory方法
初始化BeanFactory,解析XML,相当于之前的XmlBeanFactory的操作
prepareBeanFactory方法
- 设置classloader用于加载bean,设置表达式解析器,设置资源编辑注册器
- 添加ApplicationContextAwareProcessor这个BeanPostProcessor。取消ResourceLoaderAware、ApplicationEventPublisherAware、MessageSourceAware、ApplicationContextAware、EnvironmentAware这5个接口的自动注入。因为ApplicationContextAwareProcessor把这5个接口的实现工作做了
- 注册依赖,如一个bean的属性中含有ApplicationEventPublisher(beanFactory),则会将beanFactory的实例注入进去。ResourceLoader、ApplicationEventPublisher、ApplicationContext这3个接口对应的bean都设置为当前的Spring容器
- 注入一些其它信息的bean,比如environment、systemProperties等
postProcessBeanFactory方法
提供子类覆盖的额外处理,即子类处理自定义的BeanFactoryPostProcess
不同的Spring容器做不同的操作。
AnnotationConfigEmbeddedWebApplicationContext类
@Override
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 调用父类EmbeddedWebApplicationContext的实现
super.postProcessBeanFactory(beanFactory);
// 查看basePackages属性,如果设置了会使用ClassPathBeanDefinitionScanner去扫描basePackages包下的bean并注册
if (this.basePackages != null && this.basePackages.length > 0) {
this.scanner.scan(this.basePackages);
}
// 查看annotatedClasses属性,如果设置了会使用AnnotatedBeanDefinitionReader去注册这些bean
if (this.annotatedClasses != null && this.annotatedClasses.length > 0) {
this.reader.register(this.annotatedClasses);
}
}
父类EmbeddedWebApplicationContext
@Override
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
beanFactory.addBeanPostProcessor(
new WebApplicationContextServletContextAwareProcessor(this));
beanFactory.ignoreDependencyInterface(ServletContextAware.class);
}
invokeBeanFactoryPostProcessors方法
激活各种BeanFactory处理器,包括BeanDefinitionRegistryBeanFactoryPostProcessor和普通的BeanFactoryPostProcessor
在Spring容器中找出实现了BeanFactoryPostProcessor接口的processor并执行。Spring容器会委托给PostProcessorRegistrationDelegate的invokeBeanFactoryPostProcessors方法执行。
registerBeanPostProcessors方法
注册拦截Bean创建的Bean处理器,即注册BeanPostProcessor,不是BeanFactoryPostProcessor。
注意,这里仅仅是注册,并不会执行对应的方法,将在bean的实例化时执行对应的方法。
从Spring容器中找出的BeanPostProcessor接口的bean,并设置到BeanFactory的属性中。之后bean被实例化的时候会调用这个BeanPostProcessor。
该方法委托给了PostProcessorRegistrationDelegate类的registerBeanPostProcessors方法执行
initMessageSource方法
初始化上下文中的资源文件,如国际化文件的处理等
initApplicationEventMulticaster方法
在Spring容器中初始化事件广播器,事件广播器用于事件的发布。
EventPublishingRunListener这个SpringApplicationRunListener会监听事件,
发生contextPrepared事件的时候EventPublishingRunListener会把事件广播器注入到BeanFactory中。
所以initApplicationEventMulticaster不再需要再次注册,只需要拿出BeanFactory中的事件广播器然后设置到Spring容器的属性中即可。
onRefresh方法
该方法中会去创建内嵌的Servlet容器,这里既是启动tomcat
private void createEmbeddedServletContainer() {
EmbeddedServletContainer localContainer = this.embeddedServletContainer;
ServletContext localServletContext = getServletContext();
if (localContainer == null && localServletContext == null) {
EmbeddedServletContainerFactory containerFactory = getEmbeddedServletContainerFactory();
this.embeddedServletContainer = containerFactory
.getEmbeddedServletContainer(getSelfInitializer());
}
else if (localServletContext != null) {
try {
getSelfInitializer().onStartup(localServletContext);
}
catch (ServletException ex) {
throw new ApplicationContextException("Cannot initialize servlet context",
ex);
}
}
initPropertySources();
}
registerListeners方法
把Spring容器内的时间监听器和BeanFactory中的时间监听器都添加的事件广播器中,并且广播出去。
finishBeanFactoryInitialization方法
实例化BeanFactory中已经被注册但是未实例化的所有实例(懒加载的不需要实例化)。即生成环境所需要的Bean。
实例化的过程各种BeanPostProcessor开始起作用。
finishRefresh方法
初始化生命周期处理器DefaultLifecycleProcessor,DefaultLifecycleProcessor含有start方法和stop方法,spring启动的时候调用start方法开始生命周期,spring关闭的时候调用stop方法来结束生命周期,通常用来配置后台程序,启动后一直运行。
启动所有实现了Lifecycle接口的类。
通过spring的事件发布机制发布ContextRefreshedEvent事件。
2.1.7广播
listeners.finished(context, null);
2.1.8计时结束
stopWatch.stop();