Springboot启动流程
@SpringBootApplication
public class WarmApplication {
public static void main(String[] args) {
SpringApplication.run(WarmApplication.class, args);
}
}
该代码块主要有两个值得注意的地方,1. SpringApplication 2. SpringApplication.run方法。对于@SpringBootApplication以后再做分析。
1 SpringApplication
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();
}
- this.webApplicationType = WebApplicationType.deduceFromClasspath();
WebApplicationType 包含 NONE ,SERVLET,REACTIVE 三种 - setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
使用 SpringFactoriesLoader 在应用的 classpath 中查找并加载所有可用的 ApplicationContextInitializer,作用在容器调用refrence方法的时候,会调用initialize方法 - setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
使用 SpringFactoriesLoader 在应用的 classpath 中查找并加载所有可用的 ApplicationListener。作用ApplicationContext事件机制是观察者设计模式的实现,通过ApplicationEvent类和ApplicationListener接口,可以实现ApplicationContext事件处理。 - this.mainApplicationClass = deduceMainApplicationClass()
推断出main方法所在类。
run方法6步
- 获取监听器SpringApplicationRunListeners 通过SpringApplicationRunListener作为key找到value
SpringApplicationRunListeners listeners = getRunListeners(args);
- 构造应用上下文路径(环境集合,包含系统,jdk,自定义属性信息,如application.yml)加载environment对象中,需要用到通过environment中获取。
context = createApplicationContext();
(1)通过应用类型(WebApplicationType),创建不同的应用对象 StandardServletEnvironment
(2)构造环境对象environment 1)Sytem environment 2)根据配置环境(prod,val,dev)激活相应的配置 ,加载环境
(3)banner的配置,加载
(4)构造应用上下文对象ConfigurableApplicationContext。IOC容器也会创建beanFactory
- 完成bean的创建,主类
prepareContext(context, environment, listeners, applicationArguments, printedBanner); 生成启动类的单列加载到容器中。 postProcessApplicationContext(context)[setConversionService转换器] applyInitializers(context) 对初始化器进行启动,并执行 listeners.contextPrepared(context) 向监听器发送已准备好的时间 load(context, sources.toArray(new Object[0])) 把核心启动类生成单例bean注册到IOC BeanDefinition beanDefinitionMap this.annotatedReader = new AnnotatedBeanDefinitionReader(registry); - refreshContext(context) 其他单列加载到IOC
启动bean过程中完成bean的创建存在IOC postProcessBeanFactory(beanFactory);bean的后置处理器,可以修改beanDefinition的一些属性 invokeBeanFactoryPostProcessors(beanFactory);
SpringBean的生命周期
Spring Bean的生命周期只有四个阶段。实例化和属性赋值对应构造方法和setter方法的注入,初始化和销毁是用户能自定义扩展的两个阶段。
- 实例化 Instantiation
- 属性赋值 Populate
- 初始化 Initialization
- 销毁 Destruction
if (instanceWrapper == null) {
instanceWrapper = this.createBeanInstance(beanName, mbd, args);
}
try {
populateBean(beanName, mbd, instanceWrapper);
if (exposedObject != null) {
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
}
从AbstractAutowireCapableBeanFactory # doCreateBean方法中可以看到bean创建的过程。 bean的销毁,是在容器关闭时调用ConfigurableApplicationContext#close()
细节梳理
第一:在bean生命周期创建前后执行。
实现了这些接口的Bean会切入到多个Bean的生命周期中。正因为如此,这些接口的功能非常强大,Spring内部扩展也经常使用这些接口,例如自动注入以及AOP的实现都和他们有关。
BeanPostProcessor InstantiationAwareBeanPostProcessor
这两是Spring扩展中最重要的两个接口!InstantiationAwareBeanPostProcessor作用于实例化阶段的前后,BeanPostProcessor作用于初始化阶段的前后。正好和第一、第三个生命周期阶段对应。通过图能更好理解:  InstantiationAwareBeanPostProcessor
try {
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
@Nullable
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
Object bean = null;
if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
Class<?> targetType = determineTargetType(beanName, mbd);
if (targetType != null) {
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
if (bean != null) {
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
}
}
mbd.beforeInstantiationResolved = (bean != null);
}
return bean;
}
spring aop替换对象的时候并不在postProcessBeforeInstantiation替换对象,而是在 postProcessAfterInitialization处理的,也就是applyBeanPostProcessorsAfterInitialization这个方法里面,想了解详细的小朋友可以去看下
@Nullable
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
if (result != null) {
return result;
}
}
}
return null;
}
postProcessAfterInstantiation调用点,忽略无关代码:
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
boolean continueWithPropertyPopulation = true;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
continueWithPropertyPopulation = false;
break;
}
}
}
}
}
第二大类:只调用一次的接口
Aware类型的接口 生命周期接口
无所不知的Aware Aware类型的接口的作用就是让我们能够拿到Spring容器中的一些资源。基本都能够见名知意,Aware之前的名字就是可以拿到什么资源,例如BeanNameAware可以拿到BeanName,以此类推。调用时机需要注意:所有的Aware方法都是在初始化阶段之前调用的! Aware接口众多,这里同样通过分类的方式帮助大家记忆。 Aware接口具体可以分为两组,至于为什么这么分,详见下面的源码分析。如下排列顺序同样也是Aware接口的执行顺序,能够见名知意的接口不再解释。 Group1
- BeanNameAware
- BeanClassLoaderAware
- BeanFactoryAware
Group2
- EnvironmentAware
- EmbeddedValueResolverAware 这个知道的人可能不多,实现该接口能够获取Spring EL解析器,用户的自定义注解需要支持spel表达式的时候可以使用,非常方便。
- ApplicationContextAware(ResourceLoaderAware\ApplicationEventPublisher- Aware\MessageSourceAware) 这几个接口可能让人有点懵,实际上这几个接口可以一起记,其返回值实质上都是当前的ApplicationContext对象,因为ApplicationContext是一个复合接口,如下
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
MessageSource, ApplicationEventPublisher, ResourcePatternResolver {}
Aware调用时机
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
invokeAwareMethods(beanName, bean);
Object wrappedBean = bean;
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
invokeInitMethods(beanName, wrappedBean, mbd);
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
return wrappedBean;
}
可以看到并不是所有的Aware接口都使用同样的方式调用。Bean××Aware都是在代码中直接调用的,而ApplicationContext相关的Aware都是通过BeanPostProcessor#postProcessBeforeInitialization()实现的。感兴趣的可以自己看一下ApplicationContextAwareProcessor这个类的源码,就是判断当前创建的Bean是否实现了相关的Aware方法,如果实现了会调用回调方法将资源传递给Bean。
BeanPostProcessor的调用时机也能在这里体现,包围住invokeInitMethods方法,也就说明了在初始化阶段的前后执行。
关于Aware接口的执行顺序,其实只需要记住第一组在第二组执行之前就行了。
InitializingBean
对应生命周期的初始化阶段,在上面源码的invokeInitMethods(beanName, wrappedBean, mbd);方法中调用。 有一点需要注意,因为Aware方法都是执行在初始化方法之前,所以可以在初始化方法中放心大胆的使用Aware接口获取的资源,这也是我们自定义扩展Spring的常用方式。 除了实现InitializingBean接口之外还能通过注解或者xml配置的方式指定初始化方法,至于这几种定义方式的调用顺序其实没有必要记。因为这几个方法对应的都是同一个生命周期,只是实现方式不同,我们一般只采用其中一种方式。
DisposableBean
类似于InitializingBean,对应生命周期的销毁阶段,以ConfigurableApplicationContext#close()方法作为入口,实现是通过循环取所有实现了DisposableBean接口的Bean然后调用其destroy()方法 。
|