目录
- SpringBoot IoC启动流程、初始化过程及Bean生命周期各个阶段的作用
- 简述
- 首先明确IoC容器是啥
- 准备-SpringApplication的实例化
- 启动-SpringApplication的成员方法run()
- 上下文与bean容器与IoC容器
- BeanFactory的实例化
- prepareContext()方法
- refreshContext()方法——刷新Spring应用上下文
- BeanDefinition到bean实例的转化——bean生命周期的触发
- createBeanInstance创建bean实例
- populateBean自动注入
- initializeBean 初始化bean
- 总结
SpringBoot IoC启动流程、初始化过程及Bean生命周期各个阶段的作用
简述
在ssm框架时期,Spring的bean配置大都是xml形式的,但现在SpringBoot因为其优秀的特性,如嵌入Tomcat、Jetty;提供“starter”依赖,自动装配等,而广泛流行。SpringBoot也就是给Spring包了一层皮,事先替我们准备好Spring所需要的环境及一些基础。因本人所在效率工程线的基础财务团队均是使用SpringBoot框架进行研发,所以,我想以SpringBoot为切入点阐述IoC容器的启动流程。
Ps:这是前期自己看源码时候的积累,趁此机会将之前的积累转化为了一篇文档,撸源码的时候是以bean为主线的,忽略了一些细节,分析执行流程会比较长,可以直接翻到最后看总结。
首先明确IoC容器是啥
Spring IoC容器就是负责创建对象,管理对象,装配对象,配置对象,并且管理这些对象的整个生命周期的调控系统。通俗的理解就是使用前通过文件或其他方式来映射依赖对象与被依赖对象之间的关系,包括属性默认值的填充等等,由Spring去处理,然后生成大量的实例对象,屏蔽其他细节,在外界看来它就像一个存放对象的容器。
我将从SpringBoot的run方法开始,阐述IoC容器的启动流程
准备-SpringApplication的实例化
@SpringBootApplication
@Slf4j
public class DemoApplication {
public static void main(String[] args) {
log.info("spring boot开始启动...");
try {
ApplicationContext ctx = SpringApplication.run(DemoApplication.class, args);
String[] activeProfiles = ctx.getEnvironment().getActiveProfiles();
for (String profile : activeProfiles) {
log.info("当前环境为:"+profile);
}
log.info("spring boot启动成功...");
} catch (Exception e) {
log.error("spring boot启动失败...",e);
}
}
}
SpringApplication.run()的方法创建了SpringApplication的实例:
//构造器
public SpringApplication(ResourceLoader resourceLoader, Class>... primarySources) {
// 设置资源加载器
this.resourceLoader = resourceLoader;
// 设置主要资源类
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 推断当前应用的类型
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 设置ApplicationContext的初始化器
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 设置Application监听器
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 推断并设置主类
this.mainApplicationClass = deduceMainApplicationClass();
}
在构造器中主要干了:
- 推断当前应用类型
- 设置ApplicationContext初始化器、Application监听器
- 根据堆栈来推断当前main方法所在的主类
总结来说,主要做了应用类型的推断,为之后的Application创建、Environment创建打基础。
启动-SpringApplication的成员方法run()
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
// 声明一个Context容器
ConfigurableApplicationContext context = null;
Collection exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
//获取监听器
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//创建并配置Environment(这个过程会加载application配置文件)
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
configureIgnoreBeanInfo(environment);
//SpringBoot留下的彩蛋,会在启动时打图案
Banner printedBanner = printBanner(environment);
//根据应用类型创建对应的Context容器,对一般的Web应用来说会创建Servlet容器
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
// 刷新Context容器之前的准备
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
//刷新Context容器
refreshContext(context);
// 刷新Context容器之后处理
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
//...
}
// Context容器refresh完毕发布
listeners.started(context);
//执行所有的Runner运行器
callRunners(context, applicationArguments);
}
catch (Throwable ex) {//...}
try {
// Context启动完毕,Runner运行完毕发布
listeners.running(context);
}
catch (Throwable ex) {//...}
return context;
}
我们知道,SpringApplication的静态方法最终是去构造了一个SpringApplication实例对象,并调用了SpringApplication的成员方法run,这个run主要搞了这些事情:
- 首先会从spring.factories配置文件中获取SpringApplicationRunListener监听器并启动监听器;
- 而后就会去创建Environment——这个时候会去加载application配置文件
- 紧接着创建ApplicationContext——通过createApplicationContext()方法
- 对ApplicationContext进行refreshContext的事前准备——prepareContext()方法
- 对ApplicationContext进行refreshContext
- 对ApplicationContext进行refreshContext之后的处理——afterRefresh()
- 发布ApplicationContext的refreshContext完毕的事件
- 触发runner
- 最后发布refresh完毕、runner执行完毕的事件
总的来看,SpringApplication的run()就是为了创建并配置好一个ApplicationContext,我们一般称它为上下文。为了更好的切题,我在这说一下我对上下文与bean容器与IoC的理解:
上下文与bean容器与IoC容器
在大众的理解中,容器应该是一个空间的概念,是用于存放具体东西的一个数据结构。在spring中,存放的是Bean。BeanFactory是提供了一个空间用于存放Bean,所以BeanFactory才是Bean所在的主要容器,不是ApplicationContext。ApplicationContext一般称之为"上下文"。所谓上下文,其实就是spring定义的应用程序的事件发生场所。
而ApplicationContext上下文与Bean容器既然不是一个东西,那他们的之间的关系可以通过代码和类图一目了然:
public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {
// 默认BeanFactory的实现
private final DefaultListableBeanFactory beanFactory;
public GenericApplicationContext() {
this.beanFactory = new DefaultListableBeanFactory();
}
// 省略
}
我们看到BeanFactory是被组合在ApplicationContext当中的,所以可以说它们存在一种组合关系。也就是说应用上下文中包含着Bean容器。
我们看到ApplicationContext和BeanFactory还存在着继承关系,结合上面的组合关系,我们可以知道对内的话ApplicationContext的BeanFactory相关实现会由内部组合的BeanFactory的实现类来完成具体工作。
对于BeanFactory来说,它提供的是最基本的IoC容器的功能。作为开发人员常用的ApplicationContext来说,除了有容器的基本功能外,它还提供很多附加功能,是一个高级形态意义的IoC容器。
——————《Spring 技术内幕:27页》
明确了IoC容器这个概念,接下来就以BeanFactory为主线来看SpringApplication的成员方法run()对beanFactory做了什么
BeanFactory的实例化
从先前讲述的SpringApplication run()流程中知道:第3步会通过createApplicationContext()方法来创建一个ApplicationContext实例。并从先前讲述的BeanFactory与ApplicationContext关系知道,他们之间是组合、继承关系。
拿它的一个默认实现GenericApplicationContext来看,从GenericApplicationContext的构造器中:
//GenericApplicationContext构造器
public GenericApplicationContext() {
this.beanFactory = new DefaultListableBeanFactory();
}
可以知道,在通过createApplicationContext()创建一个ApplicationContext实例的时候,同时会new一个BeanFactory实例(DefaultListableBeanFactory)。进入DefaultListableBeanFactory类中可以看到成员定义:
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
//...
/** Map from dependency type to corresponding autowired value. */
private final Map, Object> resolvableDependencies = new ConcurrentHashMap<>(16);
/** Map of bean definition objects, keyed by bean name. */
private final Map beanDefinitionMap = new ConcurrentHashMap<>(256);
/** Map of singleton and non-singleton bean names, keyed by dependency type. */
private final Map, String[]> allBeanNamesByType = new ConcurrentHashMap<>(64);
/** Map of singleton-only bean names, keyed by dependency type. */
private final Map, String[]> singletonBeanNamesByType = new ConcurrentHashMap<>(64);
/** List of bean definition names, in registration order. */
private volatile List beanDefinitionNames = new ArrayList<>(256);
/** List of names of manually registered singletons, in registration order. */
private volatile Set manualSingletonNames = new LinkedHashSet<>(16);
/** Cached array of bean definition names in case of frozen configuration. */
@Nullable
private volatile String[] frozenBeanDefinitionNames;
/** Whether bean definition metadata may be cached for all beans. */
private volatile boolean configurationFrozen = false;
//...
}
看到成员变量的定义也就大体清楚了,用于IoC容器的底层数据结构就是一个个ConcurrentHashMap。
其实,从代码中写的bean配置到最终的Java对象中间大体是这样的过程:Bean配置 --> BeanDefinition --> Bean对象,
bean的配置可以是xml配置,也可以是java配置。BeanDefinition配置在内存中数据对象,也是Bean的元数据。在springboot启动过程当中,在refresh上下文这个步骤将会解析xml配置以及java配置,从而把Bean的配置解析成为BeanDefinition,这个过程又称为生成Bean元数据。
如果是懒加载情况下,refresh只是把BeanDefinition注册到BeanFactory中,而不是把Bean注册到BeanFactory中。在调用上下文的getBean的时候才会去根据BeanDefinition生成具体的bean对象。
接下来看一看run()方法的第4步——refreshContext前的准备——prepareContext()方法与第5步ApplicationContext的refreshContext对容器做了什么:
prepareContext()方法
private void prepareContext(ConfigurableApplicationContext context,
ConfigurableEnvironment environment,
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments,
Banner printedBanner
) {
//省略
//从Spring上下文获得BeanFactory
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
// 注册args参数为单例bean
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
// 注册banner为单例bean
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
// 加载main方法所在类
Set
其实prepareContext方法主要逻辑包含了三块:
- 基本的初始化,如设置Environment,调用ApplicationContextInitializer接口的实现类...
- 注册现有的对象为单例bean,如args、banner
- load()方法加载main方法所在的主类
load方法中,先是获得了BeanDefinitionLoader,然后去加载资源。(Spring的bean资源来自各种地方,如xml、annotation等,那么这些bean在配置的时候也就是对bean进行定义,而这些定义映射到内存中的对象就是BeanDefinition的对象,Spring后续会根据BeanDefinition再获取具体的bean。)
然后BeanDefinitionLoader会将主类加载成BeanDefinition,然后注册到ApplicationContext的beanFactory当中。
refreshContext()方法——刷新Spring应用上下文
接着run()方法的第5步开始执行refreshContext()方法,正式进入Spring生命周期,SpringBoot核心特性也随之启动,
其中也包括了加载BeanDefinition,并完成bean的注册,实例化非懒加载的bean等。
从run()方法的refreshContext(context)跟进到refresh(context),再跟进到((AbstractApplicationContext) applicationContext).refresh(),可以看到真正做事情的bstractApplicationContext的refresh方法的流程:
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 刷新前准备,设置flag、时间,初始化properties等
prepareRefresh();
// 获取ApplicationContext中组合的BeanFactory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 设置类加载器,添加后置处理器等准备
prepareBeanFactory(beanFactory);
try {
// 供子类实现的后置处理
postProcessBeanFactory(beanFactory);
// 调用Bean工厂的后置处理器
invokeBeanFactoryPostProcessors(beanFactory);
// 注册Bean的后置处理器
registerBeanPostProcessors(beanFactory);
// 初始化消息源
initMessageSource();
// 初始化事件广播
initApplicationEventMulticaster();
// 供之类实现的,初始化特殊的Bean
onRefresh();
// 注册监听器
registerListeners();
// 实例化所有的(non-lazy-init)单例Bean
finishBeanFactoryInitialization(beanFactory);
// 发布刷新完毕事件
finishRefresh();
}
catch (BeansException ex) {
// 省略
} finally {
// 省略
}
}
}
BeanDefinition
其中,invokeBeanFactoryPostProcessors(beanFactory)方法主要实现了将annotation/xml的Bean配置转化为Spring的BeanDefinition的过程。
继续从invokeBeanFactoryPostProcessors(beanFactory)跟进到PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors()):
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory,
List beanFactoryPostProcessors
) {
//
if (beanFactory instanceof BeanDefinitionRegistry) {
// 省略
while (reiterate) {
// 调用BeanDefinition注册的后置处理器
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
//省略
}
//
} else {
//
}
//
}
可以看到,调用后置处理器的时候会调用到注册BeanDefinition的后置处理器。也就是从这里开始作为BeanDefinition的注册入口。
跟进invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
private static void invokeBeanDefinitionRegistryPostProcessors(
Collection extends BeanDefinitionRegistryPostProcessor> postProcessors,
BeanDefinitionRegistry registry
) {
//其中的postProcessor就是ConfigurationClassPostProcessor,断点调试可以看到具体的实例
for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
postProcessor.postProcessBeanDefinitionRegistry(registry);
}
}
通过断点调试,可以看到ConfigurationClassPostProcessor完成BeanDefinition注册这项工作。继续跟进ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry(registry)方法,进入processConfigBeanDefinitions(registry);
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List configCandidates = new ArrayList<>();
String[] candidateNames = registry.getBeanDefinitionNames();
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
// 省略
} else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
// 默认仅有主类被添加
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
// 省略
// 解析被 @Configuration 注解的类
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory,
this.problemReporter,
this.environment,
this.resourceLoader,
this.componentScanBeanNameGenerator,
registry);
Set candidates = new LinkedHashSet<>(configCandidates);
//
do {
// 解析的核心方法
parser.parse(candidates);
parser.validate();
// 省略
candidates.clear();
//
} while (!candidates.isEmpty());
//
}
在先前的介绍的prepareContext方法的核心逻辑里,main方法所在的主类将会被作为BeanDefinition加载到BeanFactory当中,在这里,主类将被ConfigurationClassParser解析器所解析。进入parser.parse(candidates)方法:
public void parse(Set configCandidates) {
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
if (bd instanceof AnnotatedBeanDefinition) {
// 主类的解析将从这里进入
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
} else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
} else {
parse(bd.getBeanClassName(), holder.getBeanName());
}
} catch (BeanDefinitionStoreException ex) {}
catch (Throwable ex) {}
}
this.deferredImportSelectorHandler.process();
}
protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
processConfigurationClass(new ConfigurationClass(metadata, beanName));
}
可以看到主类作为配置类的解析过程将从processConfigurationClass(new ConfigurationClass(metadata, beanName))这里开始。
跟进processConfigurationClass方法:
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
// ...
// 由main方法所在的主类开始,向超类逐层向上递归解析
SourceClass sourceClass = asSourceClass(configClass);
do {
// 解析单个配置类的核心逻辑
sourceClass = doProcessConfigurationClass(configClass, sourceClass);
} while (sourceClass != null);
// ...
}
doProcessConfigurationClass(configClass, sourceClass);方法将会完成解析的主要工作,同时又会返回一个新的sourceClass用于解析。而这个新的sourceClass会是当前上一个sourceClass的父类。所在解析过程是一个递归过程,由主类开始,逐层向上递归解析处理。
doProcessConfigurationClass(configClass, sourceClass)方法中主要干了两件事:
- 解析@ComponentScan注解,扫描目标路径,将路径下注解配置的bean解析为BeanDefinition并注册到BeanFactory中
- 获取超类向上递归
我们从doProcessConfigurationClass(configClass, sourceClass)方法,跟进到this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName())方法,获得了扫描器和扫描路径,执行scanner.doScan(StringUtils.toStringArray(basePackages))方法:
protected Set doScan(String... basePackages) {
Set beanDefinitions = new LinkedHashSet<>();
for (String basePackage : basePackages) {
// 扫描获取BeanDefinition
Set candidates = findCandidateComponents(basePackage);
for (BeanDefinition candidate : candidates) {
//...
if (checkCandidate(beanName, candidate)) {
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
// 注册BeanDefinition到BeanFactory
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
findCandidateComponents方法将会根据扫描路径获取BeanDefinition,而扫描出来的BeanDefinition将会进入注册方法registerBeanDefinition。
在注册方法registerBeanDefinition(definitionHolder, this.registry)中:
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder,
BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {
String beanName = definitionHolder.getBeanName();
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// 省略
}
//进入到registerBeanDefinition()
protected void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) {
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, registry);
}
//进入到 BeanDefinitionReaderUtils.registerBeanDefinition()中
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder,
BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {
String beanName = definitionHolder.getBeanName();
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// 省略
}
从图中可以看到,BeanFactory的默认实现类DefaultListableBeanFactory实现了BeanDefinitionRegistry,所以DefaultListableBeanFactory即是BeanDefinition的注册位置。此时,代码正在将我在com.axin.demo路径下CacheConfig类中定义的名称为"cacheConfig"的bean注册到DefaultListableBeanFactory。
跟进到DefaultListableBeanFactory的registerBeanDefinition方法:
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
private final Map beanDefinitionMap = new ConcurrentHashMap<>(256);
public void registerBeanDefinition(
String beanName,
BeanDefinition beanDefinition) throws BeanDefinitionStoreException {
//...
if (existingDefinition != null) {
//...
} else {
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
synchronized (this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition);
// ...
}
} else {
//...
}
//...
}
// ...
}
}
最终,也就是将BeanDefinition添加到一个key-value的集合当中,这样就完成了注册工作。
在开始的refresh()源码中,会调用:
finishBeanFactoryInitialization(beanFactory);
来实例化所有的(non-lazy-init)单例Bean,其实调用到底层你会发现,对bean实例化的触发是由接下来介绍的getBean(String name)所完成的。
BeanDefinition到bean实例的转化——bean生命周期的触发
如果是懒加载情况下,refresh只是把BeanDefinition注册到BeanFactory中,而不是把Bean注册到BeanFactory中。在调用上下文的getBean的时候才会去根据BeanDefinition生成具体的bean对象。默认情况下,Spring会在bean容器初始化的时候实例化所有的bean,他们均是由getBean(String name)所完成的:
@Override
public Object getBean(String name) throws BeansException {
//
return getBeanFactory().getBean(name);
}
上下文的getBean方法把功能实现委托给了BeanFactory,BeanFactory会通过doGetBean(name, null, null, false)来获得Bean:
protected T doGetBean(
final String name,
@Nullable final Class requiredType,
@Nullable final Object[] args,
boolean typeCheckOnly) throws BeansException {
final String beanName = transformedBeanName(name);
Object bean;
// 如果拿到已经注册的单例Bean,直接返回结果
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
//
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
} else {
//...
try {
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
//...
// 创建单例
if (mbd.isSingleton()) {
// 回调创建
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
} catch (BeansException ex) {
//
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
} else if (mbd.isPrototype()) {
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
// 每次创建
prototypeInstance = createBean(beanName, mbd, args);
} finally {
//
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
} else {
//...
}
} catch (BeansException ex) {
//...
}
}
//...
return (T) bean;
}
doGetBean()方法先从单例的缓存中找,如果找得到直接返回。如果找不到,那么判断是单例还是原型,如果是单例创建并缓存,如果是原型那么每次都创建新的对象。
单例缓存查询不到、同时bean采用单例模式时,触发创建单例Bean的方法
// 回调创建
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
} catch (BeansException ex) {
//
}
});
进入getSingleton()看看在哪里回调的:
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
private final Map singletonObjects = new ConcurrentHashMap<>(256);
public Object getSingleton(String beanName, ObjectFactory> singletonFactory) {
// 内置锁控制
synchronized (this.singletonObjects) {
// 双重校验
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
//...
boolean newSingleton = false;
//...
try {
// 回调创建Bean
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch (IllegalStateException ex) {
//...
}
catch (BeanCreationException ex) {
//...
} finally {
//...
}
if (newSingleton) {
// 添加单例到缓存中
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
}
这里Spring采用双重校验机制来创建单例,如果二次校验的时候发现缓存中没有Bean,那么就会回调创建的方法去创建一个Bean,然后再注册到本地堆缓存当中。
回调方法中的创建实现委托给了createBean(beanName, mbd, args)方法,它会调用doCreateBean(beanName, mbdToUse, args):
protected Object doCreateBean(
final String beanName,
final RootBeanDefinition mbd,
final @Nullable Object[] args) throws BeanCreationException {
BeanWrapper instanceWrapper = null;
//...
if (instanceWrapper == null) {
// 创建Bean实例对象
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
//...
Object exposedObject = bean;
try {
// 自动注入
populateBean(beanName, mbd, instanceWrapper);
//bean的初始化
exposedObject = initializeBean(beanName, exposedObject, mbd);
//...
} catch (Throwable ex) {
//...
}
//...
return exposedObject;
}
主要干了三件事:
- createBeanInstance(beanName, mbd, args)来创建Bean的实例对象
- populateBean(beanName, mbd, instanceWrapper)来自动注入
- initializeBean(beanName, exposedObject, mbd)来完成bean的初始化
至此,bean生命周期正式开始
createBeanInstance创建bean实例
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// ...
// 默认使用无参数构造方法获取实例
return instantiateBean(beanName, mbd);
}
进入instantiateBean(beanName, mbd):
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
implements AutowireCapableBeanFactory {
//Cgilb动态代理
private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy();
protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
try {
Object beanInstance;
final BeanFactory parent = this;
if (System.getSecurityManager() != null) {
beanInstance = AccessController.doPrivileged((PrivilegedAction
可以看到,默认是通过Cgilb动态代理的方式来实例化bean,进入getInstantiationStrategy().instantiate(mbd, beanName, parent)方法:
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
// 如果不存在需要被重写的方法,那么就不需要使用cglib重写并覆盖该类
if (!bd.hasMethodOverrides()) {
Constructor> constructorToUse;
synchronized (bd.constructorArgumentLock) {
//
}
// 通过构造方法实例化
return BeanUtils.instantiateClass(constructorToUse);
} else {
// 需要通过cglib生成
return instantiateWithMethodInjection(bd, beanName, owner);
}
}
至此,BeanDefinition就被初步创建成为了一个Bean实例对象,然后进行注入。
populateBean自动注入
所谓注入,就是对我们已实例化好的bean的属性进行赋值,有时bean中关联着其他的bean,populateBean()方法也会帮你建立bean之间的关系。
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
// ...
// 获取待注入的property,配置文件中配置的将在这里被处理
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
// 按照名字或者类型获取属性,这里会进行递归
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// 按照名字获取属性
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// 按照类型获取属性
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
PropertyDescriptor[] filteredPds = null;
if (hasInstAwareBpps) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
// 后置处理器处理@Autowired @Resource等注解
pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
}
pvs = pvsToUse;
}
}
}
// 注入属性
if (pvs != null) {
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
initializeBean 初始化bean
至此,已经完了了前2步的处理:
- 创建一个Bean的实例对象,createBeanInstance方法执行
- 处理Bean之间的依赖注入,比如@Autowired注解等。所以,populateBean方法将会先去处理注入的Bean,因此对于相互注入的Bean来说不用担心Bean的生成先后顺序问题。(Spring有自己一套解决循环依赖的方法,这里不展开了)
Bean实例生成,相互注入以后,还需要对Bean进行一些初始化操作,你会在initializeBean()方法中看到,Spring留给开发者一些可以扩展的切入点。
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction
从initializeBean()方法可以看到在bean初始化阶段都干些啥:
- 执行一些Aware方法,比如BeanNameAware的setBeanName(beanName)
- 执行BeanPostProcessor预初始化方法,例如,会执行@PostConstruct注解的方法
- 执行afterPropertiesSet()方法与自定义的inti-method
- 执行BeanPostProcessor初始化后方法
具体的:
- BeanNameAware的setBeanName()方法:如果某个Bean实现了BeanNameAware接口,那么Spring将会将Bean实例的ID传递给setBeanName()方法,在Bean类中新增一个beanName字段,并实现setBeanName()方法。
- BeanFactoryAware的setBeanFactory()方法:如果某个Bean实现了BeanFactoryAware接口,那么Spring将会将创建Bean的BeanFactory传递给setBeanFactory()方法,在Bean类中新增了一个beanFactory字段用来保存BeanFactory的值,并实现setBeanFactory()方法。
- BeanPostProcessor预初始化方法:如果某个IoC容器中增加的实现BeanPostProcessor接口的实现类Bean,那么在该容器中实例化Bean之后,执行初始化之前会调用BeanPostProcessor中的postProcessBeforeInitialization()方法执行预初始化处理。
- InitializingBean的afterPropertiesSet()方法:如果Bean实现了InitializingBean接口,那么Bean在实例化完成后将会执行接口中的afterPropertiesSet()方法来进行初始化。
- 自定义的inti-method指定的方法:如果配置文件中使用init-method属性指定了初始化方法,那么Bean在实例化完成后将会调用该属性指定的初始化方法进行Bean的初始化。
- BeanPostProcessor初始化后方法:如果某个IoC容器中增加的实现BeanPostProcessor接口的实现类Bean,那么在该容器中实例化Bean之后并且完成初始化调用后执行该接口中的postProcessorAfterInitialization()方法进行初始化后处理。
invokeAwareMethods——执行一些Aware方法
private void invokeAwareMethods(final String beanName, final Object bean) {
if (bean instanceof Aware) {
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
if (bean instanceof BeanClassLoaderAware) {
ClassLoader bcl = getBeanClassLoader();
if (bcl != null) {
((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
}
}
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
}
}
}
没啥看头,就是执行一些set方法。
applyBeanPostProcessorsBeforeInitialization——执行BeanPostProcessor预初始化方法
@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
//执行BeanPostProcessor的预初始化方法
Object current = processor.postProcessBeforeInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
遍历bean的后置处理器,执行postProcessBeforeInitialization(result, beanName)方法。
invokeInitMethods——执行afterPropertiesSet()方法与自定义的inti-method
protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
throws Throwable {
boolean isInitializingBean = (bean instanceof InitializingBean);
if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
//...
if (System.getSecurityManager() != null) {
try {
AccessController.doPrivileged((PrivilegedExceptionAction
代码一目了然,会判断执行((InitializingBean) bean).afterPropertiesSet()方法与invokeCustomInitMethod(beanName, bean, mbd)
applyBeanPostProcessorsAfterInitialization执行BeanPostProcessor初始化后方法
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
//执行BeanPostProcessor初始化后方法
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
总结
先前的一大堆简要说了下IoC的启动流程,主要是以bean实例化、初始化的主线进行的,还有一些重要的特性比如SpringBoot自动装配等没有提及,总的来说,IoC容器的主要的启动流程如下:
- SpringApplication.run方法启动,生成SpringApplication实例
- 执行SpringApplication的成员方法run(String... args)
- 首先会从spring.factories配置文件中获取SpringApplicationRunListener监听器并启动监听器;
- 而后就会去创建Environment——这个时候会去加载application配置文件
- 紧接着创建ApplicationContext——通过createApplicationContext()方法
- 对ApplicationContext进行refreshContext的事前准备——prepareContext()方法
- 对ApplicationContext进行refreshContext——对BeanDefinition的载入与注册
- 对ApplicationContext进行refreshContext之后的处理——afterRefresh()
- 发布ApplicationContext的refreshContext完毕的事件
- 触发runner
- 最后发布refresh完毕、runner执行完毕的事件
- 获得ConfigurableApplicationContext应用上下文
在启动流程中的第2.3步,对ApplicationContext进行refreshContext时,会执行AbstractApplicationContext的refresh()方法,它会在finishBeanFactoryInitialization(beanFactory)方法中实例化所有非懒加载的bean,其实底层也会调用doGetBean()方法开启bean的生命周期。
对于bean是懒加载模式的话,应用上下文加载完时,它还只是以BeanDefinition的形式存在BeanFactory中,调用getBean(String name)方法时开始bean的生命周期:
总的来说Spring bean的生命周期分为四个阶段:
- 实例化 Instantiation
- 属性赋值 Populate
- 初始化 Initialization
- 销毁 Destruction
具体的:
- 触发bean生命周期
- bean的实例化
- Bean的实例化:Bean的实例化是使用反射实现的。
- Bean属性注入:Bean实例化完成后,利用反射技术实现属性及依赖Bean的注入。
- bean的初始化
- BeanNameAware的setBeanName()方法:如果某个Bean实现了BeanNameAware接口,那么Spring将会将Bean实例的ID传递给setBeanName()方法,在Bean类中新增一个beanName字段,并实现setBeanName()方法。
- BeanFactoryAware的setBeanFactory()方法:如果某个Bean实现了BeanFactoryAware接口,那么Spring将会将创建Bean的BeanFactory传递给setBeanFactory()方法,在Bean类中新增了一个beanFactory字段用来保存BeanFactory的值,并实现setBeanFactory()方法。
- BeanPostProcessor预初始化方法:如果某个IoC容器中增加的实现BeanPostProcessor接口的实现类Bean,那么在该容器中实例化Bean之后,执行初始化之前会调用BeanPostProcessor中的postProcessBeforeInitialization()方法执行预初始化处理。
- InitializingBean的afterPropertiesSet()方法:如果Bean实现了InitializingBean接口,那么Bean在实例化完成后将会执行接口中的afterPropertiesSet()方法来进行初始化。
- 自定义的inti-method指定的方法:如果配置文件中使用init-method属性指定了初始化方法,那么Bean在实例化完成后将会调用该属性指定的初始化方法进行Bean的初始化。
- BeanPostProcessor初始化后方法:如果某个IoC容器中增加的实现BeanPostProcessor接口的实现类Bean,那么在该容器中实例化Bean之后并且完成初始化调用后执行该接口中的postProcessorAfterInitialization()方法进行初始化后处理。
- 使用Bean:此时有关Bean的所有准备工作均已完成,Bean可以被程序使用了,它们将会一直驻留在应用上下文中,直到该上下文环境被销毁。
- bean的销毁
- DisposableBean的destory()方法:如果Bean实现了DisposableBean接口,Spring将会在Bean实例销毁之前调用该接口的destory()方法,来完成一些销毁之前的处理工作。
- 自定义的destory-method指定的方法:如果在配置文件中使用destory-method指定了销毁方法,那么在Bean实例销毁之前会调用该指定的方法完成一些销毁之前的处理工作。
- End