springboot(4) 启动过程及实现对bean动态代理源码分析

【springboot(4) 启动过程及实现对bean动态代理源码分析】1.springboot启动过程分析

  • springboot启动过程run方法:
public ConfigurableApplicationContext run(String... args) {
//创建一个StopWatch对象并调用它的start方法,该类是Spring提供的一个计时器类
StopWatch stopWatch = new StopWatch();
stopWatch.start();

ConfigurableApplicationContext context = null;
FailureAnalyzers analyzers = null;

//设置系统属性java.awt.headless,这里设置为true,表示运行在服务器端
configureHeadlessProperty();

/**
* 获取SpringApplicationRunListeners对象,这个对象是一个SpringBoot事件广播器的管理者,
* 它主要是管理SpringApplicationRunListener对象的,
* SpringApplicationRunListener接口规定了SpringBoot的生命周期,并在各个生命周期广播相应的事件
* springboot默认为EventPublishingRunListener
* 具体可见另外一篇博文springboot(2)生命周期和监听器。
*/
SpringApplicationRunListeners listeners = getRunListeners(args);
//广播启动事件
listeners.starting();

try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);

//准备运行的环境,比如开发环境dev,测试环境test然后根据环境解析不同的配置文件,并广播环境准备事件
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);

//打印SpringBoot的LOGO
Banner printedBanner = printBanner(environment);

//创建SpringBoot的上下文 判断当前是否是web环境,
//如果是web程序,创建AnnotationConfigEmbeddedWebApplicationContext的实例,
//否则创建AnnotationConfigApplicationContext的实例
context = createApplicationContext();

//创建FailureAnalyzers的对象,主要是用来处理启动时发生一些异常时的一些分析
analyzers = new FailureAnalyzers(context);

//准备上下文
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
//刷新上下文
refreshContext(context);
afterRefresh(context, applicationArguments); //发送启动完成事件
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);
}
}
  • 准备运行的环境
private ConfigurableEnvironment prepareEnvironment(
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {

// 检查之前设置的webEnvironment属性,如果是web程序,那么创建一个StandardServletEnvironment对象,否则创建StandardEnvironment对象
ConfigurableEnvironment environment = getOrCreateEnvironment();

//准备运行环境配置,根据环境,比如开发环境dev,加载相关配置文件
configureEnvironment(environment, applicationArguments.getSourceArgs());

//发布运行环境加载完毕的事件
listeners.environmentPrepared(environment);
if (!this.webEnvironment) {
environment = new EnvironmentConverter(getClassLoader())
.convertToStandardEnvironmentIfNecessary(environment);
}
return environment;
}
  • 准备上下文:
private void prepareContext(ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
//设置上下文环境
context.setEnvironment(environment);

//设置上下文的beanNameGenerator和resourceLoader(如果SpringApplication有的话)
postProcessApplicationContext(context);

//利用初始化器,对上下文做初始化
//具体可见另外一篇博文 springboot (3)应用上下文初始化器ApplicationContextInitializer
applyInitializers(context);
//发布上下文准备好的事件
listeners.contextPrepared(context);

//打印启动日志
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}

//向上下文的beanFactory中注册一个singleton的bean,bean的名字是springApplicationArguments,
//bean的实例是之前实例化的ApplicationArguments对象
context.getBeanFactory().registerSingleton("springApplicationArguments",
applicationArguments);
//向上下文的beanFactory中注册一个singleton的bean,bean的名字是springBootBanner,bean的实例就是这个printedBanner
if (printedBanner != null) {
context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
}

//向上下文注册启动类的bean,也就是调用SpringApplication.run(Application.class, args); 的类,这里只有一个
Set sources = getSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[sources.size()]));

//发布上下文加载完毕事件
listeners.contextLoaded(context);
}
  • 刷新上下文
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
//为刷新上下文信息做准备。例如清空缓存,初始化属性信息,验证必要的属性等
prepareRefresh();

//获取到beanFactory,把refreshed属性设置成true,表示已经刷新了,下次再刷新就会抛出异常,不允许重复刷新,
//然后给beanFactory设置serializationId,就是之前通过ContextIdApplicationContextInitializer生成的id
//然后通过getBeanFactory方法拿到上下文的beanFactory(之前创建上下文的时候,创建了一个DefaultListableBeanFactory对象)
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

//对beanFactory设置相关参数
prepareBeanFactory(beanFactory);

try {
//为beanFactory添加后置处理器WebApplicationContextServletContextAwareProcessor,并忽略ServletContextAware
postProcessBeanFactory(beanFactory);

//扫描路径下的所有类,如果被@Component等注解的类,生成BeanDefinition对象,并回调BeanFactoryPostProcessor后置处理器
invokeBeanFactoryPostProcessors(beanFactory);

//注册bean的后置处理器,这些后置处理器将在bean的创建过程中被调用
registerBeanPostProcessors(beanFactory);

//初始化上下文的消息源
initMessageSource();

//初始化事件广播器,springboot在广播事件的时候,默认是同步的,如果想要实现事件异步传播,
//就需要自定义一个名叫applicationEventMulticaster的bean,
//这里就是看是否有自定义的bean,如果有则用用户创建的,否则就用默认的。
initApplicationEventMulticaster();

//初始化其他特殊的bean,比如创建serverlet容器相关的bean(TomcatEmbeddedServletContainerFactory)
onRefresh();

//想事件广播器中添加各种事件监听器
registerListeners();

//实例化所有单例bean
finishBeanFactoryInitialization(beanFactory);

//发布容器事件,结束刷新过程
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();
}
}
}
  • 对beanFactory设置相关参数prepareBeanFactory
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
//设置用于加载bean的类加载器
beanFactory.setBeanClassLoader(getClassLoader());
//设置可以解析bean表达式的 表达式解析器 (使用"#{xxx}"配置的属性)
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
//添加属性注册器
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

//添加ApplicationContextAwareProcessor后置处理器
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

//设置了6个忽略自动注入的接口,为什么要忽略呢?因为上一步添加的ApplicationContextAwareProcessor,会在bean初始化前后调用相应的方法,
//而相应的方法里有如下6个设置对应的接口
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

//设置了几个自动装配的特殊规则,如果注入的是BeanFactory类型,则注入beanFactory对象,
//如果是ResourceLoader、ApplicationEventPublisher、ApplicationContext类型,则注入当前对象(Spring上下文 - context)
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);

//注册ApplicationListenerDetector,应用监听检查器,
//该检测器的主要作用是在bean初始化后,会检查该bean是否是ApplicationListener,
//如果是,那么会验证它是否是单例,如果不是单例,那么删除singletonNames中对应的key,singletonNames中记录了bean的名称及是否是单例
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

// Detect a LoadTimeWeaver and prepare for weaving, if found.
if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
// Set a temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}

//注册几个特殊的bean
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
}
if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
}
if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
}
}
run方法步骤总结:
1.获取spring应用执行监听器(SpringApplicationRunListeners)
2.利用spring应用执行监听器广播启动事件
3.准备运行的环境(dev,test),根据环境解析不同的配置文件
3.1 检查webEnvironment属性,如果是web程序,那么创建一个StandardServletEnvironment对象,否则创建StandardEnvironment对象
3.2 准备运行环境配置,根据环境(dev,test),加载相关配置文件
3.3 利用spring应用执行监听器广播运行环境加载完毕的事件
4.创建spring应用上下文,如果是web程序,创建web应用上下文实例
5.准备spring应用上下文
5.1 利用spring初始化器,对上下文做初始化操作
5.2 利用spring应用执行监听器广播上下文准备好的事件
5.3 向beanFactory注册springApplicationArguments和springBootBanner单例bean
5.4 向上下文注册启动类的bean,也就是调用SpringApplication.run(Application.class, args); 的类
5.5 利用spring应用执行监听器广播上下文加载完毕事件
6.刷新spring应用上下文
6.1 为刷新上下文信息做准备。例如清空缓存,初始化属性信息,验证必要的属性等
6.2 获取应用上下文的beanFactory
6.3 对beanFactory设置相关参数
6.4 为beanFactory添加后置处理器WebApplicationContextServletContextAwareProcessor,并忽略ServletContextAware
6.5 调用beanFactory的后置处理器
6.6 注册bean的后置处理器,这些后置处理器将在bean的创建过程中被调用
6.7 初始化事件广播器(EventMulticaster),看是否有自定义的事件广播bean(applicationEventMulticaster),如果有则使用自定义的,否则就用默认的。
6.8 初始化其他特殊的bean,比如创建serverlet容器相关的bean
6.9 向事件广播器EventMulticaster中添加各种事件监听器
6.10 实例化所有单例bean
6.11 结束刷新,利用EventMulticaster广播上下文刷新完成事件
7.执行应用runner(或命令行runner)
8.利用spring应用执行监听器广播启动完成事件



    推荐阅读