Spring IoC之AbstractBeanFactory(二)

简介: Spring IoC之AbstractBeanFactory(二)

各 scope 的 bean 创建


在 Spring 中存在着不同的 scope,默认是 singleton ,还有 prototype、request 等等其他的 scope ,接下来我们分析一下它们的创建过程。


singleton


Spring 的 scope 默认为 singleton,其初始化的代码如下:  


if (mbd.isSingleton()) {
    sharedInstance = this.getSingleton(beanName, () -> {
        try {
            return this.createBean(beanName, mbd, args);
        } catch (BeansException var5) {
            this.destroySingleton(beanName);
            throw var5;
        }
    });
    bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
复制代码


第一部分分析了从缓存中获取单例模式的 bean,但是如果缓存中不存在呢?则需要从头开始加载 bean,这个过程由 getSingleton(beanName,  singletonFactory) 实现。


public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    Assert.notNull(beanName, "Bean name must not be null");
    // 全局加锁
    synchronized(this.singletonObjects) {
        // 从缓存中检查一遍
        // 因为 singleton 模式其实就是复用已经创建的 bean 所以这步骤必须检查
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null) {
            ....
            // 加载前置处理
            this.beforeSingletonCreation(beanName);
            boolean newSingleton = false;
            boolean recordSuppressedExceptions = this.suppressedExceptions == null;
            if (recordSuppressedExceptions) {
                this.suppressedExceptions = new LinkedHashSet();
            }
            try {
                // 初始化 bean
                // 这个过程其实是调用 createBean() 方法,调试的时候可以发现
                singletonObject = singletonFactory.getObject();
                newSingleton = true;
            } catch (IllegalStateException var16) {
                singletonObject = this.singletonObjects.get(beanName);
                if (singletonObject == null) {
                    throw var16;
                }
            } catch (BeanCreationException var17) {
                  ....
            } finally {
                if (recordSuppressedExceptions) {
                    this.suppressedExceptions = null;
                }
                // 后置处理
                this.afterSingletonCreation(beanName);
            }
            // 加入缓存中
            if (newSingleton) {
                this.addSingleton(beanName, singletonObject);
            }
        }
        return singletonObject;
    }
}
复制代码


其实这个过程并没有真正创建 bean,仅仅只是做了一部分准备和预处理步骤,真正获取单例 bean 的方法其实是由 singletonFactory.getObject() 这部分实现,而 singletonFactory 由回调方法产生。那么这个方法做了哪些准备呢?


  1. 再次检查缓存是否已经加载过,如果已经加载了则直接返回,否则开始加载过程。
  2. 调用 beforeSingletonCreation() 记录加载单例 bean 之前的加载状态,即前置处理。
  3. 调用参数传递的 ObjectFactory 的 getObject() 实例化 bean。
  4. 调用 afterSingletonCreation() 进行加载单例后的后置处理。
  5. 将结果记录并加入值缓存中,同时删除加载 bean 过程中所记录的一些辅助状态。
    这里我们看一下 addSingleton()方法


protected void addSingleton(String beanName, Object singletonObject) {
    synchronized(this.singletonObjects) {
        this.singletonObjects.put(beanName, singletonObject);
        this.singletonFactories.remove(beanName);
        this.earlySingletonObjects.remove(beanName);
        this.registeredSingletons.add(beanName);
    }
}
复制代码


结合循环依赖章节中所讲,这一步就是清除二级和三级缓存中的数据,添加到一级缓存中,位于一级缓存中的单例数据可以多次被调用。

接着来重点关注 AbstractAutowireCapableBeanFactory 类中实现的 createBean()方法,其定义如下:


protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
    if (this.logger.isTraceEnabled()) {
        this.logger.trace("Creating instance of bean '" + beanName + "'");
    }
    RootBeanDefinition mbdToUse = mbd;
    // 确保此时的 bean 已经被解析了
    Class<?> resolvedClass = this.resolveBeanClass(mbd, beanName, new Class[0]);
    if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
        // 如果获取的class 属性不为null,则克隆该 BeanDefinition
        // 主要是因为该动态解析的 class 无法保存到到共享的 BeanDefinition
        mbdToUse = new RootBeanDefinition(mbd);
        mbdToUse.setBeanClass(resolvedClass);
    }
    try {
        // 验证和准备覆盖方法
        mbdToUse.prepareMethodOverrides();
    } catch (BeanDefinitionValidationException var9) {
        throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(), beanName, "Validation of method overrides failed", var9);
    }
    Object beanInstance;
    try {
        // 给 BeanPostProcessors 一个机会用来返回一个代理类而不是真正的类实例
        // AOP 的功能就是基于这个地方
        beanInstance = this.resolveBeforeInstantiation(beanName, mbdToUse);
        if (beanInstance != null) {
            return beanInstance;
        }
    } catch (Throwable var10) {
        throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName, "BeanPostProcessor before instantiation of bean failed", var10);
    }
    try {
        // 执行真正创建 bean 的过程
        beanInstance = this.doCreateBean(beanName, mbdToUse, args);
        if (this.logger.isTraceEnabled()) {
            this.logger.trace("Finished creating instance of bean '" + beanName + "'");
        }
        return beanInstance;
    } catch (ImplicitlyAppearedSingletonException | BeanCreationException var7) {
        throw var7;
    } catch (Throwable var8) {
        throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", var8);
    }
}
复制代码


主要过程如下:

  • 解析指定 BeanDefinition 的 class
  • 处理 override 属性
  • 实例化的前置处理
  • 创建 bean


prepareMethodOverrides()方法涉及到 BeanDefinition,后续会做介绍。


resolveBeforeInstantiation() 的作用是给 BeanPostProcessors 后置处理器返回一个代理对象的机会,其实在调用该方法之前 Spring 一直都没有创建 bean ,那么这里返回一个 bean 的代理类有什么作用呢?作用体现在后面的 if 判断:


if (beanInstance != null) {
    return beanInstance;
}
复制代码


如果代理对象不为空,则直接返回代理对象,这一步骤有非常重要的作用,Spring 后续实现 AOP 就是基于这个地方判断的。


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;
}
复制代码


这个方法核心就在于 applyBeanPostProcessorsBeforeInstantiation()applyBeanPostProcessorsAfterInitialization() 两个方法,before 为实例化前的后处理器应用,after 为实例化后的后处理器应用。最终还是由 BeanPostProcessor 接口实现类来完成相应的工作。


接下来就该最核心的创建 bean 的工作,该过程有 doCreateBean() 实现,如下:


protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
        // BeanWrapper是对Bean的包装,其接口中所定义的功能很简单包括设置获取被包装的对象,获取被包装bean的属性描述器
        BeanWrapper instanceWrapper = null;
        // 单例模型,则从未完成的 FactoryBean 缓存中删除
        if (mbd.isSingleton()) {
            instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName);
        }
        // 使用合适的实例化策略来创建新的实例:工厂方法、构造函数自动注入、简单初始化
        if (instanceWrapper == null) {
            instanceWrapper = this.createBeanInstance(beanName, mbd, args);
        }
        // 包装的实例对象
        Object bean = instanceWrapper.getWrappedInstance();
        // 包装的实例对象的类型
        Class<?> beanType = instanceWrapper.getWrappedClass();
        if (beanType != NullBean.class) {
            mbd.resolvedTargetType = beanType;
        }
        // 检测是否有后置处理
        // 如果有后置处理,则允许后置处理修改 BeanDefinition
        synchronized(mbd.postProcessingLock) {
            if (!mbd.postProcessed) {
                try {
                    this.applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
                } catch (Throwable var17) {
                    ....
                }
                mbd.postProcessed = true;
            }
        }
        // 解决单例模式的循环依赖
        // 单例模式 & 运行循环依赖&当前单例 bean 是否正在被创建
        boolean earlySingletonExposure = mbd.isSingleton() && this.allowCircularReferences && this.isSingletonCurrentlyInCreation(beanName);
        if (earlySingletonExposure) {
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references");
            }
            this.addSingletonFactory(beanName, () -> {
                return this.getEarlyBeanReference(beanName, mbd, bean);
            });
        }
        Object exposedObject = bean;
        try {
            // 对 bean 进行填充,将各个属性值注入,其中,可能存在依赖于其他 bean 的属性
            // 则会递归初始依赖 bean
            this.populateBean(beanName, mbd, instanceWrapper);
            // 调用初始化方法
            exposedObject = this.initializeBean(beanName, exposedObject, mbd);
        } catch (Throwable var18) {
            if (var18 instanceof BeanCreationException && beanName.equals(((BeanCreationException)var18).getBeanName())) {
                throw (BeanCreationException)var18;
            }
            throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", var18);
        }
        /**
         * 循环依赖处理
         */
        if (earlySingletonExposure) {
            // 获取 earlySingletonReference
            Object earlySingletonReference = this.getSingleton(beanName, false);
            // 只有在存在循环依赖的情况下,earlySingletonReference 才不会为空
            if (earlySingletonReference != null) {
                // 如果 exposedObject 没有在initializeBean初始化方法中被改变,也就是没有被增强
                if (exposedObject == bean) {
                    exposedObject = earlySingletonReference;
                } else if (!this.allowRawInjectionDespiteWrapping && this.hasDependentBean(beanName)) {
                    String[] dependentBeans = this.getDependentBeans(beanName);
                    Set<String> actualDependentBeans = new LinkedHashSet(dependentBeans.length);
                    String[] var12 = dependentBeans;
                    int var13 = dependentBeans.length;
                    for(int var14 = 0; var14 < var13; ++var14) {
                        String dependentBean = var12[var14];
                        if (!this.removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                            actualDependentBeans.add(dependentBean);
                        }
                    }
                    if (!actualDependentBeans.isEmpty()) {
                        ....
                    }
                }
            }
        }
        try {
            // 注册 bean
            this.registerDisposableBeanIfNecessary(beanName, bean, mbd);
            return exposedObject;
        } catch (BeanDefinitionValidationException var16) {
           .....
        }
    }
复制代码


整体的思路:


  1. 如果是单例模式,则清除 factoryBeanInstanceCache 缓存,同时返回 BeanWrapper 实例对象,当然如果存在。


  1. 如果缓存中没有 BeanWrapper 或者不是单例模式,则调用 createBeanInstance() 实例化 bean,主要是将 BeanDefinition 转换为 BeanWrapper


  1. 单例模式的循环依赖处理 ,在之前的文章有详细分析过,这里总结一下:


  • createBeanInstance() 实例化 bean,赋零值
  • populateBean() 属性填充
  • 循环依赖的处理
  • initializeBean() 初始化 bean,包括前置、后置处理器的调用


创建完 bean 实例后,还会执行 getObjectForBeanInstance()方法,这个方法在缓存中获取单例 bean 一节有介绍到。


原型模式


else if (mbd.isPrototype()) {
    var11 = null;
    Object prototypeInstance;
    try {
        this.beforePrototypeCreation(beanName);
        prototypeInstance = this.createBean(beanName, mbd, args);
    } finally {
        this.afterPrototypeCreation(beanName);
    }
    bean = this.getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
复制代码


原型模式的初始化过程很简单:直接创建一个新的实例就可以了。过程如下:


  1. 调用 beforeSingletonCreation() 记录加载原型模式 bean 之前的加载状态,即前置处理。
  2. 调用 createBean() 创建一个 bean 实例对象。
  3. 调用 afterSingletonCreation() 进行加载原型模式 bean 后的后置处理。
  4. 调用 getObjectForBeanInstance() 从 bean 实例中获取对象。


原型模式下,执行 createBean()相对来说简单一些,这里就不多做介绍了。不过关于循环依赖队列中存在原型模式的 bean,需要注意一下,这里我们还是拿之前的案例来进行测试,做一下修改。


修改 beans.xml 文件,将其中的一个 bean 定义为原型模式:


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="car" class="com.msdn.bean.AbstractCar"  p:brand="宝马" p:money-ref="money" />
    <bean id="person" class="com.msdn.bean.Person" p:name="herish" p:car-ref="car" />
    <bean id="money" class="com.msdn.bean.Money" p:classification="工资" p:person-ref="person" scope="prototype"/>
</beans>
复制代码


新的测试代码:


@Test
public void cycleRely(){
    ClassPathResource resource = new ClassPathResource("config/beans.xml");
    BeanFactory beanFactory = new XmlBeanFactory(resource);
    Person person = (Person) beanFactory.getBean("person");
    System.out.println(person);
    Money money = (Money) beanFactory.getBean("money");
    Money money2 = (Money) beanFactory.getBean("money");
    System.out.println(money == money2);
    AbstractCar car = (AbstractCar) beanFactory.getBean("car");
    AbstractCar car2 = (AbstractCar) beanFactory.getBean("car");
    System.out.println(car == car2);
}
复制代码


运行结果为:


Person{name='herish', 拥有一辆car=AbstractCar{brand='宝马', money=Money{classification='工资', person=herish}}}
false
true
复制代码


从结果来看,貌似没什么问题,money 对象确实也不再是单例,循环依赖也处理成功了。接下来我们做一下修改:


@Test
public void cycleRely(){
ClassPathResource resource = new ClassPathResource("config/beans.xml");
BeanFactory beanFactory = new XmlBeanFactory(resource);
//        Person person = (Person) beanFactory.getBean("person");
//        System.out.println(person);
Money money = (Money) beanFactory.getBean("money");
Money money2 = (Money) beanFactory.getBean("money");
System.out.println(money == money2);
AbstractCar car = (AbstractCar) beanFactory.getBean("car");
AbstractCar car2 = (AbstractCar) beanFactory.getBean("car");
System.out.println(car == car2);
}
复制代码


运行该代码会报错:


org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'money' defined in class path resource [config/beans.xml]: Cannot resolve reference to bean 'person' while setting bean property 'person'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'person' defined in class path resource [config/beans.xml]: Cannot resolve reference to bean 'car' while setting bean property 'car'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'car' defined in class path resource [config/beans.xml]: Cannot resolve reference to bean 'money' while setting bean property 'money'; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'money': Requested bean is currently in creation: Is there an unresolvable circular reference?
复制代码


调试该代码可以发现问题,由于mbd.isSingleton()(此处mbd为money对应的bean)为false,导致没有将相应的数据加入到三级缓存中,再次调用 getSingleton(beanName, allowEarlyReference)方法返回结果为 null,导致进行到 isPrototypeCurrentlyInCreation(beanName)方法时抛出异常。


其他作用域


String scopeName = mbd.getScope();
Scope scope = (Scope)this.scopes.get(scopeName);
if (scope == null) {
    throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
    Object scopedInstance = scope.get(beanName, () -> {
        this.beforePrototypeCreation(beanName);
        Object var4;
        try {
            var4 = this.createBean(beanName, mbd, args);
        } finally {
            this.afterPrototypeCreation(beanName);
        }
        return var4;
    });
    bean = this.getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
} catch (IllegalStateException var23) {
    throw new BeanCreationException(beanName, "Scope '" + scopeName + "' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton", var23);
}
复制代码


核心流程和原型模式一样,只不过获取 bean 实例是由 scope.get() 实现,如下:


public Object get(String name, ObjectFactory<?> objectFactory) {
    // 获取 scope 缓存
    Map<String, Object> scope = this.threadScope.get();
    Object scopedObject = scope.get(name);
    if (scopedObject == null) {
        scopedObject = objectFactory.getObject();
        // 加入缓存
        scope.put(name, scopedObject);
    }
    return scopedObject;
}
复制代码


AbstractBeanFactory 类中对于 getBean(name)方法的讲解终于结束了,这也是 bean 加载的过程。


目录
相关文章
|
6天前
|
XML Java 数据格式
Spring框架入门:IoC与DI
【5月更文挑战第15天】本文介绍了Spring框架的核心特性——IoC(控制反转)和DI(依赖注入)。IoC通过将对象的创建和依赖关系管理交给容器,实现解耦。DI作为IoC的实现方式,允许外部注入依赖对象。文章讨论了过度依赖容器、配置复杂度等常见问题,并提出通过合理划分配置、使用注解简化管理等解决策略。同时,提醒开发者注意过度依赖注入和循环依赖,建议适度使用构造器注入和避免循环引用。通过代码示例展示了注解实现DI和配置类的使用。掌握IoC和DI能提升应用的灵活性和可维护性,实践中的反思和优化至关重要。
22 4
|
6天前
|
Java 测试技术 开发者
Spring IoC容器通过依赖注入机制实现控制反转
【4月更文挑战第30天】Spring IoC容器通过依赖注入机制实现控制反转
22 0
|
6天前
|
XML Java 程序员
Spring特性之二——IOC控制反转
Spring特性之二——IOC控制反转
16 4
|
6天前
|
安全 Java 开发者
在Spring框架中,IoC和AOP是如何实现的?
【4月更文挑战第30天】在Spring框架中,IoC和AOP是如何实现的?
24 0
|
6天前
|
XML Java 程序员
什么是Spring的IoC容器?
【4月更文挑战第30天】什么是Spring的IoC容器?
20 0
|
6天前
|
Java Spring 容器
【Spring系列笔记】IOC与DI
IoC 和 DI 是面向对象编程中的两个相关概念,它们主要用于解决程序中的依赖管理和解耦问题。 控制反转是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入和依赖查找。
35 2
|
6天前
|
Java 测试技术 数据库连接
Spring中ioc的优点
总之,Spring中的IoC提供了一种更加灵活、可维护、可测试和可扩展的方式来管理组件之间的依赖关系,从而提高了应用程序的质量和可维护性。这使得开发人员能够更专注于业务逻辑而不是底层的技术细节。
32 1
|
6天前
|
Java 应用服务中间件 Spring
|
6天前
|
XML Java 数据格式
Spring IOC的源码解析
【4月更文挑战第17天】Spring IOC(控制反转)的核心功能是通过依赖注入(DI)来管理对象的创建和它们之间的依赖关系。要深入理解Spring IOC的工作原理,我们可以从其源码分析入手,特别是关注如何创建和管理Bean以及依赖注入的实现
22 1
|
6天前
|
XML Java 数据格式
Spring IOC—基于XML配置和管理Bean 万字详解(通俗易懂)
Spring 第二节 IOC—基于XML配置和管理Bean 万字详解!。
99 5