IOC图解设计结构
这里我们就对Spring的IOC的核心过程展开探讨,整体过程就如下图所示,其过程为:
-
加载Bean的配置(比如xml配置) -
根据Bean的定义加载生成Bean的实例 -
然后将bean实例存入到bean容器中 -
后续上下文需要加载,则从bean容器中获取
IOC源码分析
准备
为了解析源码,我们首先需要配置配置文件spring-config.xml。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userService" class="com.example.springboot.spring.ioc.UserService"></bean>
</beans>
编写一个UserService类
public class UserService {
public String hello() {
return "Hello World! zayton!";
}
}
编写一个测试案例,然后debug
进入源码开始阅读;由于源码复杂度高,所以我们主要讲解核心步骤。
public class Entrance {
/**
* 基于配置文件的依赖注入测试
*
* @param args
*/
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
// retrieve configured instance
UserService userService = context.getBean("userService", UserService.class);
// use configured instance
try {
userService.hello();
} catch (Exception e) {
// e.printStackTrace();
}
}
}
从ClassPathXmlApplicationContext看IOC的整体流程
主要做了以下几个步骤:
-
初始化资源解析器和父容器 -
设置配置文件路径 -
初始化容器
public ClassPathXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {
//初始化资源解析器和父容器
super(parent);
//设置配置文件路径
setConfigLocations(configLocations);
//初始化容器
if (refresh) {
refresh();
}
}
初始化容器(重要)
IOC容器对bean定义资源的载入是从refresh()函数开始的,主要作用是:在创建IOC容器前,如果存在容器,需要将就容器销毁和关闭,然后建立新的容器,对新容器进行初始化,将bean定义资源加载到新容器。
public void refresh() throws BeansException, IllegalStateException {
// 来个锁,不然 refresh() 还没结束,你又来个启动或销毁容器的操作,那不就乱套了嘛
synchronized (this.startupShutdownMonitor) {
StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
// 准备工作,记录下容器的启动时间、标记“已启动”状态、处理配置文件中的占位符
prepareRefresh();
// 这步比较关键,这步完成后,配置文件就会解析成一个个 Bean 定义,注册到 BeanFactory 中,
// 当然,这里说的 Bean 还没有初始化,只是配置信息都提取出来了,
// 注册也只是将这些信息都保存到了注册中心(说到底核心是一个 beanName-> beanDefinition 的 map)
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 设置 BeanFactory 的类加载器,添加几个 BeanPostProcessor,手动注册几个特殊的 bean
prepareBeanFactory(beanFactory);
try {
// 允许子类扩展
postProcessBeanFactory(beanFactory);
StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
// 调用 BeanFactoryPostProcessor 各个实现类的 postProcessBeanFactory(factory) 回调方法
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
beanPostProcess.end();
// 初始化当前ApplicationContext 国际化。
initMessageSource();
// 初始化当前ApplicationContext 的事件广播器
initApplicationEventMulticaster();
// 钩子方法,具体的子类可以在这里初始化一些特殊的 Bean
onRefresh();
// 注册事件监听器
registerListeners();
// 初始化所有的 singleton beans(除了lazy-init)
finishBeanFactoryInitialization(beanFactory);
// 初始化完成
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// 销毁已创建的单例的Beans
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();
contextRefresh.end();
}
}
}
初始化BeanFactory之obtainFreshBeanFactory
我们先看obtainFreshBeanFactory()方法,它首先会刷新容器,然后返回一个新的容器,具体步骤如下所示。
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
//销毁并关闭旧的beanFactory,创建新的beanFactory
refreshBeanFactory();
//返回刚刚创建的beanFactory
return getBeanFactory();
}
在refreshBeanFactory()方法中,它主要做的事情是先销毁容器,然后创建一个DefaultListableBeanFactory
的beanFactory,然后将bean定义信息(BeanDefinition)
加载到这个beanFactory中。然后将beanFactory设置为当前创建的DefaultListableBeanFactory
。
protected final void refreshBeanFactory() throws BeansException {
// 如果ApplicationContext中已经加载过BeanFactory了,销毁所有Bean,关闭BeanFactory
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
//创建一个DefaultListableBeanFactory
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
// 设置 BeanFactory 的两个配置属性:是否允许 Bean 覆盖、是否允许循环引用
customizeBeanFactory(beanFactory);
// 加载 Bean 到 BeanFactory 中
loadBeanDefinitions(beanFactory);
this.beanFactory = beanFactory;
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
初始化Beanfactory之loadBeanDefinitions
loadBeanDefinitions主要是创建了BeanDefinition读取器
,然后用这个读取器加载BeanDefinition
,通过这个读取器加载XML配置方式中的bean定义资源和构造函数里配置的bean配置文件。
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// 创建XmlBeanDefinitionReader,即bean读取器
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// 配置环境、资源加载、解析器
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
//初始化 BeanDefinitionReader(提供给子类覆写)
initBeanDefinitionReader(beanDefinitionReader);
//加载BeanDefinition
loadBeanDefinitions(beanDefinitionReader);
}
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
//加载xml配置方式中的bean定义的资源
Resource[] configResources = getConfigResources();
if (configResources != null) {
reader.loadBeanDefinitions(configResources);
}
//加载构造函数方式中的xml配置的资源
String[] configLocations = getConfigLocations();
if (configLocations != null) {
reader.loadBeanDefinitions(configLocations);
}
}
具体加载loadBeanDefinitions的过程
由于上面我们使用ClassPathXmlApplicationContext作为例子分析,因此上述步骤程序只会执行reader.loadBeanDefinitions(configLocations);
分支。获取到一个resource数组,我们可以拿着resources
这个配置信息数组去加载BeanDefinition
。
public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
//忽略细节
//模式匹配类型的解析器,这种方式是加载多个满足匹配条件的资源
if (resourceLoader instanceof ResourcePatternResolver) {
//忽略细节
try {
// 获取到要加载的资源
Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
//返回加载到的个数
int count = loadBeanDefinitions(resources);
//忽略细节
}
else {
//忽略细节
}
}
Spring将Bean定义资源转换为Document对象
我们继续深入源码,会发现在XmlBeanDefinitionReader类中可以看到doLoadBeanDefinitions()方法,这个方法主要作用是载入Bean定义资源文件,然后将Bean定义资源转换为Document对象,具体过程由documentLoader实现。
public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,
ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {
// 创建文件解析器工厂
DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);
if (logger.isTraceEnabled()) {
logger.trace("Using JAXP provider [" + factory.getClass().getName() + "]");
}
// 创建文档解析器
DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
return builder.parse(inputSource); // 解析
}
protected DocumentBuilderFactory createDocumentBuilderFactory(int validationMode, boolean namespaceAware)
throws ParserConfigurationException {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(namespaceAware);
// 设置解析XML的校验
if (validationMode != XmlValidationModeDetector.VALIDATION_NONE) {
factory.setValidating(true);
if (validationMode == XmlValidationModeDetector.VALIDATION_XSD) {
// Enforce namespace aware for XSD...
factory.setNamespaceAware(true);
try {
factory.setAttribute(SCHEMA_LANGUAGE_ATTRIBUTE, XSD_SCHEMA_LANGUAGE);
}
catch (IllegalArgumentException ex) {
ParserConfigurationException pcex = new ParserConfigurationException(
"Unable to validate using XSD: Your JAXP provider [" + factory +
"] does not support XML Schema. Are you running on Java 1.4 with Apache Crimson? " +
"Upgrade to Apache Xerces (or Java 1.5) for full XSD support.");
pcex.initCause(ex);
throw pcex;
}
}
}
return factory;
}
Spring如何基于Document进行对象解析
首先通过document对象获取document元素,然后调用doRegisterBeanDefinitions方法
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
doRegisterBeanDefinitions(doc.getDocumentElement());
}
这时候基于这个配置文件的内容,将这些字符串的信息生成数据转为BeanDefinition
protected void doRegisterBeanDefinitions(Element root) {
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);
//忽略....
preProcessXml(root);
// 主要调用这个方法,从Document的根元素开始进行Bean定义的Document对象
parseBeanDefinitions(root, this.delegate);
postProcessXml(root);
this.delegate = parent;
}
再parseBeanDefinitions()方法中会调用parseDefaultElement(),将xml为bean的标签数据取出来生成bean定义信息
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
// 如果元素节点是<Import>导入元素,进行导入解析
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
// 如果元素节点是<Alias>别名元素,进行别名解析
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
// 如果元素节点<Bean>元素, 按照Spring的Bean规则解析元素
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
// 如果元素节点<Beans>元素,即它是嵌套类型的
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// 递归解析
doRegisterBeanDefinitions(ele);
}
}
元素节点元素转为BeanDefinition的细节
将bean标签生成BeanDefinition然后存入BeanDefinitionHolder中。通过BeanDefinitionHolder加载bean定义信息,然后注册到容器中。
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// 注册最终的装饰实例,这是BeanDefinition向IOC容器注册的入口
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// 完成BeanDefinition注册后,向容器发送注册完成事件
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
将bean注册到IOC容器
上文说过通过BeanDefinitionHolder获取bean信息,而后调用registerBeanDefinition将bean注册到IOC中
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
// 将beandefinition及其名字注册到容器里
String beanName = definitionHolder.getBeanName();
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// 如果存在别名则逐个注册进容器
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}
IOC容器本质上就是一个beanDefinitionMap,然后将BeanDefinition put到map中
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
private final Map<String, BeanDefinitionHolder> mergedBeanDefinitionHolders = new ConcurrentHashMap<>(256);
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
//忽略....
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
// 如果已经注册
if (existingDefinition != null) {
// 检查是否可以覆盖
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
}
//忽略....
// 覆盖
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
//忽略....
//重置所有已经注册过的BeanDefinition的缓存
this.frozenBeanDefinitionNames = null;
}
if (existingDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
else if (isConfigurationFrozen()) {
clearByTypeCache();
}
}
IOC常见问题
Spring是如何解决循环依赖的呢?
循环依赖说白了就是需要我中有你,你中有我,最后谁都不愿成全对方;就如下图所示,想要创建AService
就得先拥有BService
,可BService
的创建却又需要AService
,搁这互相套娃呢?那么它具体是怎么解决循环依赖的呢?循环依赖无非是双方都需要对象类信息而已,我们在创建AService时发现需要BService,完全可以将半成品的AService方到缓存中,然后创建BService,让BService拿着缓存中的AService先完成创建,然后回到AService这边继续完成后续工作。为此Spring为了解决单例循环依赖
而设置了三级缓存,代码如下:
/** Cache of singleton objects: bean name --> bean instance */
//存的是完整的单例对象
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);
/** Cache of early singleton objects: bean name --> bean instance */
//存的是半成品单例对象
private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);
/** Cache of singleton factories: bean name --> ObjectFactory */
//单例工厂的缓存
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);
我们首先从缓存中尝试获取bean,就是从三级缓存查找
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// Spring首先从singletonObjects(一级缓存)中尝试获取
Object singletonObject = this.singletonObjects.get(beanName);
//判断当前单例bean是否正在创建中
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
// 一级缓存没有,就去二级缓存找
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
// 二级缓存也没有,就去三级缓存找
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 如果三级缓存中有的话,就把他放到到二级缓存中
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
如果缓存中都没有,那么就需要创建bean,创建bean从以下代码开始。
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
});
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
上述创建bean的代码主要步骤如下:
-
调用createBean方法,在方法内部的doCreateBean(),通过createBeanInstance创建一个原始对象。 -
调用addSingletonFactory()添加bean 工厂对象到singletonFactories缓存。 -
调用populateBean方法向原始 bean 对象中填充属性,并解析依赖。 -
最后getSingleton中通过singletonFactory.getObject()创建singletonObject,最后调用addSingleton将完整的bean对象存入到singletonObjects(一级缓存)中。
二级缓存是否可以解决循环依赖问题
到这里可能会有人疑惑二级缓存貌似就可以解决循环依赖问题,为什么还需要三级缓存呢?三级缓存的目的主要是为了解决AOP的特性,是为了后置处理。
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
// 这么一大段就这句话是核心,也就是当bean要进行提前曝光时,
// 给一个机会,通过重写后置处理器的getEarlyBeanReference方法,来自定义操作bean
// 值得注意的是,如果提前曝光了,但是没有被提前引用,则该后置处理器并不生效!!!
// 这也正式三级缓存存在的意义,否则二级缓存就可以解决循环依赖的问题
exposedObject = bp.getEarlyBeanReference(exposedObject, beanName);
}
}
return exposedObject;
}
Spring为何不能解决非单例属性之外的循环依赖
prototype情况
假设我们遇到循环依赖的bean是多例的,我们在AService创建得不到BService再到BService创建得不到AService时,去创建AService时,会遇到下面这段代码。
//当前多例bean处于创建中,说明存在循环依赖,直接报错
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
构造器循环依赖
构造器注入形成的循环依赖:也就是AService需要在BService的构造函数中完成初始化,BService也需要在AService的构造函数中完成初始化。而Spring解决循环依赖依靠的是Bean的“中间态”这个概念,而这个中间态指的是已经实例化,但还没初始化的状态。实例化的过程又是通过构造器创建的,如果AService还没创建好出来,怎么可能提前曝光。循环依赖难以解决。
Spring bean生命周期
生命周期大致分为几个阶段:创建->属性填充->初始化bean->使用->销毁。我们简单介绍下这些阶段所做的事:
-
创建阶段主要实例化bean。 -
属性填充阶段主要是依赖注入,将当前对象依赖的bean对象,从容器中找出填充到对应的属性中。 -
初始化bean阶段包括回调各种aware接口、回调各种初始化方法、生成AOP对象。 -
使用阶段则是bean创建完成,提供服务的阶段。 -
销毁阶段,主要是对bean进行销毁。
创建bean
首先Spring是通过反射来创建对象的,不过如果我们提供了Supplier
或者工厂方法
,Spring也会直接使用我们提供的创建方法。第一阶段实例化bean在源码中的doCreateBean
方法中createBeanInstance(beanName, mbd, args)
,如下所示:
// 源码位于 AbstractAutowireCapableBeanFactory.java
if (instanceWrapper == null) {
//instanceWrapper 即实例化后的对象
//mbd 这里面包含这个类的所有实例化需要的信息
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// 再次解析BeanDefinition的class,确保class已经被解析
Class<?> beanClass = resolveBeanClass(mbd, beanName);
// 1: 如果提供了Supplier,通过Supplier产生对象
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName);
}
// 2: 如果有工厂方法,使用工厂方法产生对象
// 在@Configration配置@Bean的方法,也会被解析为FactoryMethod
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
//...省略部分代码
// 3: 推断构造方法
// 3.1 执行后置处理器,获取候选构造方法
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
// 3.2 需要自动注入的情况
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
return autowireConstructor(beanName, mbd, ctors, args);
}
// 3.3 默认使用没有参数的构造方法
return instantiateBean(beanName, mbd);
}
根据源码分析,我们可以把上述代码分为几个步骤:
-
判断是否提供了supplier,如果提供则通过supplier产生对象 -
判断是否提供了工厂方法,如果提供则通过工厂方法产生对象 -
如果都没有则判断构造方法有几个,若只有一个则直接使用该构造方法 -
若有多个构造方法,会判断有没有加了 Autowired
注解的构造参数,若都没有则使用无参构造;若有且是加了@Autowired(required=true)
注解的构造方法则使用该方法;若只有加Autowired
的构造方法,则会从所有加了Autowired
的构造方法中综合打分,选择一个匹配参数最多,类型最准确的构造方法。
属性填充
该阶段是Spring的核心功能之一:依赖注入,包括自动注入
、@Autowired注入(通过类型方式注入)
、@Resource注入(通过名称注入)
等,Spring会根据bean的注入模型(默认不自动注入),选择根据名称自动注入还是根据类型自动注入。然后调用InstantiationAwareBeanPostProcessor#postProcessProperties()完成@Autowired和@Resource的属性注入。
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
// 省略部分代码
// 获取bean的注入类型
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
// 1: 自动注入
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
// 根据名称注入
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
// 根据类型注入
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
// 2: 调用BeanPostProcessor,完成@Autowired @Resource属性填充
PropertyDescriptor[] filteredPds = null;
if (hasInstAwareBpps) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
// 重点: 完成@Autowired @Resource属性填充
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
if (filteredPds == null) {
// 需要注入的属性,会过滤掉Aware接口包含的属性(通过ignoreDependencyInterface添加)
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
}
pvs = pvsToUse;
}
}
}
// 3: 依赖检查
if (needsDepCheck) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
checkDependencies(beanName, mbd, filteredPds, pvs);
}
// 4: 将属性应用到bean中
if (pvs != null) {
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
初始化bean
该阶段包含比较多的步骤,整体大致分为:
-
检查当前创建的bean是否有实现 xxAware
相关的接口,如果有则调用用户的实现 -
如果有没有继承 BeanPostProcessor
则会调用用户实现BeanPostProcessor
的postProcessBeforeInitialization
-
然后看看bean有没有继承 InitializingBean
接口,如果有则调用afterPropertiesSet
方法 -
如果用户配置 init-method
方法则调用这个方法 -
然后调用 BeanPostProcessor
的postProcessAfterInitialization
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
//
// 如果bean实现了BeanNameAware、BeanClassLoaderAware 或 BeanFactoryAware 接口则回调
invokeAwareMethods(beanName, bean);
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// ApplicationContextAwareProcessor: 其他Aware方法的回调
// InitDestroyAnnotationBeanPostProcessor: @PostConstruct方法的回调
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
// 处理bean中定义的init-method和@bean(initMethod)的init方法回调
//或者如果 bean 实现了 InitializingBean 接口,调用 afterPropertiesSet()
invokeInitMethods(beanName, wrappedBean, mbd);
}
// 调用after方法
// 重点: AOP生成代理对象
if (mbd == null || !mbd.isSynthetic()) {
// BeanPostProcessor 的 postProcessAfterInitialization 回调
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
初始化完成后,bean就会被放入单例池中,如果后续有使用该bean的地方,则直接从单例池中获取,不会再次创建bean(仅限单例)。
bean的销毁阶段
在创建bean的时候,会判断如果bean是DisposableBean、AutoCloseable的子类,或者有 destroy-method等,会注册为可销毁的bean,在容器关闭时,调用对应的方法进行bean的销毁。
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
// ...省略代码
try {
// 为bean注册DisposableBean,在容器关闭时,调用destory()
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
总结成一张图就是如下所示,Spring 容器中Bean 的生命周期流程
参考文献
[Spring IOC 容器源码分析]https://javadoop.com/post/spring-ioc
[Spring进阶- Spring IOC实现原理详解之IOC初始化流程]https://www.pdai.tech/md/spring/spring-x-framework-ioc-source-2.html
[烂大街的 Spring 循环依赖问题,你真以为自己会了吗?]https://zhuanlan.zhihu.com/p/223028634
[聊透Spring bean的生命周期]https://juejin.cn/post/7155884227714613285?searchId=2023080117131985BA48BA99B03F054099#heading-0
原文始发于微信公众号(写代码的ZaytonSquid):Spring入门心经之第一章 IOC详解
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/246263.html