4. bean的加载

2019-04-14  本文已影响0人  凭窗听风

spring源码学习笔记,要点归纳和代码理解

前言

经过了三节的的铺垫,终于到了对象创建的核心部分了,bean的整个加载过程代码量非常大,逻辑错综复杂,因此这部分我的原则是以理解和把控关键过程和逻辑为基本,不局限于细节实现,以AbstractBeanFactorydoGetBean方法为骨架阅读抽象出的方法代码,对于重点逻辑详细解析.

bean加载的整体流程

首先贴出精简了异常处理逻辑的doGetBean方法代码

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
            @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
        // 转换beanName,将alias或id或className统一转换为beanName
        final String beanName = transformedBeanName(name);
        Object bean;

        // Eagerly check singleton cache for manually registered singletons.
        // 从缓存中尝试获取实例
        Object sharedInstance = getSingleton(beanName);
        if (sharedInstance != null && args == null) {
            // 缓存中取出的不一定是创建好的实例,有可能是提早曝光加入到缓存的factoryBean
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
        } else {
            // Fail if we're already creating this bean instance:
            // We're assumably within a circular reference.
            // 当前bean如果在创建过程中,则发生循环依赖,抛出异常
            if (isPrototypeCurrentlyInCreation(beanName)) {
                throw new BeanCurrentlyInCreationException(beanName);
            }

            // Check if bean definition exists in this factory.
            // 检测父类工厂,此处为了保证bean的父类能够被先于子实例加载
            BeanFactory parentBeanFactory = getParentBeanFactory();
            if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
                // Not found -> check parent.
                String nameToLookup = originalBeanName(name);
                if (parentBeanFactory instanceof AbstractBeanFactory) {
                    return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
                            nameToLookup, requiredType, args, typeCheckOnly);
                }
                else if (args != null) {
                    // Delegation to parent with explicit args.
                    return (T) parentBeanFactory.getBean(nameToLookup, args);
                }
                else if (requiredType != null) {
                    // No args -> delegate to standard getBean method.
                    return parentBeanFactory.getBean(nameToLookup, requiredType);
                }
                else {
                    return (T) parentBeanFactory.getBean(nameToLookup);
                }
            }
            // 标记已创建
            if (!typeCheckOnly) {
                markBeanAsCreated(beanName);
            }

                final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
                checkMergedBeanDefinition(mbd, beanName, args);

                // Guarantee initialization of beans that the current bean depends on.
                String[] dependsOn = mbd.getDependsOn();
                if (dependsOn != null) {
                    for (String dep : dependsOn) {
                        if (isDependent(beanName, dep)) {
                            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                    "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
                        }
                        registerDependentBean(dep, beanName);
                        getBean(dep);
                        
                    }
                }

                // Create bean instance.
                if (mbd.isSingleton()) { // 创建单例bean
                    sharedInstance = getSingleton(beanName, () -> {
                        return createBean(beanName, mbd, args);
                    });
                    bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
                }

                else if (mbd.isPrototype()) { // 创建多例
                    // It's a prototype -> create a new instance.
                    Object prototypeInstance = null;
                    try {
                        beforePrototypeCreation(beanName);
                        prototypeInstance = createBean(beanName, mbd, args);
                    }
                    finally {
                        afterPrototypeCreation(beanName);
                    }
                    bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
                }

                else {
                    String scopeName = mbd.getScope();
                    final Scope scope = this.scopes.get(scopeName);
                    if (scope == null) {
                        throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
                    }
                        Object scopedInstance = scope.get(beanName, () -> {
                            beforePrototypeCreation(beanName);
                            return createBean(beanName, mbd, args);
                        });
                        bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
                    
                }
            
        }

        // Check if required type matches the type of the actual bean instance.
        // 类型检查
        if (requiredType != null && !requiredType.isInstance(bean)) {
                T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
                if (convertedBean == null) {
                    throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
                }
                return convertedBean;
            
        }
        return (T) bean;
    }

整个加载过程的步骤大致如下:

  1. 转换对应的beanName
  2. 尝试从缓存中加载实例
  3. bean的实例化
  4. prototype的依赖检查
  5. 检测parentBeanFactory
  6. 将GernericBeanDefinition 转换为RootBeanDefinition
  7. 寻找依赖
  8. 针对不同scope创建bean
  9. 类型转换

循环依赖的处理

  1. 使用factoryBean封装创建对象的逻辑
  2. 将正在创建的bean对应的factoryBean暴露到缓存中
  3. 创建bean时先尝试从几个缓存中取出bean或bean的factoryBean

主要应用到四个对象和两个方法:

  1. singletonObjects: 保存创建的bean和beanName的关系
  2. singletonFactories: 保运BeanName和创建bean的工厂之间的关系
  3. earlySingletonObjects: 保存beanName和bean实例之间的关系,与singletonObjects的区别是,当一个单例bean被放到这里后,那么即使bean还在创建过程中,也可以通过getBean方法从这个缓存中获取
  4. registeredSingletons: 用来保存的当前所有已注册的bean
    DefaultSingletonBeanRegistry中的两个方法
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
        Assert.notNull(singletonFactory, "Singleton factory must not be null");
        synchronized (this.singletonObjects) {
            if (!this.singletonObjects.containsKey(beanName)) {
                this.singletonFactories.put(beanName, singletonFactory);
                this.earlySingletonObjects.remove(beanName);
                this.registeredSingletons.add(beanName);
            }
        }
    }
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        Object singletonObject = this.singletonObjects.get(beanName);
        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;
    }
  1. spring容器创建单例TestBeanA, 根据无参构造器创建,并通过ObjectFactory接口暴露getEarlyBeanReference()方法,将beanName和封装该方法的ObjectFactory添加到singletonFactory缓存中
  2. 在执行A的populateBean方法,即装配A的属性时,发现B的依赖,执行getBean(B)方法
  3. 创建单例B,将B的ObjectFactory加入到singletonFactory,之后继续执行B的populateBean,
  4. 发现依赖注入中存在TestBeanA,调用getBean(A),这时会通过getSingle(A)的方法调用到之前暴露的getEarlyBeanReference方法,这个方法如下,会返回a的实例.
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
        Object exposedObject = bean;
        if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            for (BeanPostProcessor bp : getBeanPostProcessors()) {
                if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
                    SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
                    exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
                }
            }
        }
        return exposedObject;
    }

这里附一张调用栈的截图,一目了然.


创建bean

创建bean的实现通过lambda表达式将AbstractBeanFactory的doGetBean方法封装到factoryBean中进行的.

  1. 创建bean的实例
    a. 确定构造函数
    b. 判断beanDefinition中的getMethodOverrides,决定直接反射构造bean还是通过动态代理的方式构造bean,是AOP实现的切入点
  2. 记录创建bean的ObjectFactory, 循环依赖的解决
  3. 属性注入
  4. 初始化bean
    a. 激活aware方法 -- 为实现Aware接口的的bean对象注入对应的对象
    b. 处理器的应用 -- 为BeanFactory增加BeanPostProcessor,一种增强器,在执行初始化方法之前和之后执行,可以添加业务逻辑
    c. 激活自定义的init方法 -- 配置文件的init-method配置
  5. 注册DisposableBean

后记

bean的加载可以说是spring的两大核心之一了,也是aop实现的切入点,这部分代码多多阅读,可以把控spring的整体运行原理,对于一些定制的需求也可以更灵活的实现.
对于复杂的逻辑进行分解,分成N个小函数的嵌套,每一层都是对下一层逻辑的总结和概要,这样使得每一层逻辑会变得简单容易理解.

附 测试代码

public class MyTestBean {

    private String name = "testName";

    private Integer id;

    public MyTestBean(Integer id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return "MyTestBean{" +
                "name='" + name + '\'' +
                ", id=" + id +
                '}';
    }

    public MyTestBean() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    private void init() {
        System.out.println("测试bean被初始化了");
    }
}
public abstract class LookupTestBean {

    public void doSomething() {
        System.out.println(getTestBean());
    }

    public abstract MyTestBean getTestBean();
}
<?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 name="myTestBean" class="com.pctf.beans.MyTestBean" init-method="init">
        <property name="name" value="测试对象"></property>
        <constructor-arg index="0" value="10"></constructor-arg>

    </bean>

    <bean name="lookupTestBean" class="com.pctf.beans.LookupTestBean">
        <lookup-method name="getTestBean" bean="myTestBean"></lookup-method>
    </bean>

    <beans profile="dev">

    </beans>
</beans>
public class AppTestLaunch {

    public static void main(String[] args) {
        XmlBeanFactory bf = new XmlBeanFactory( new ClassPathResource("spring-config.xml"));
        bf.addBeanPostProcessor(new PostProcessorTest());
        MyTestBean myTestBean = (MyTestBean) bf.getBean("myTestBean");
        LookupTestBean lookupTestBean = (LookupTestBean) bf.getBean("lookupTestBean");
        lookupTestBean.doSomething();
        System.out.println(myTestBean.getName());
    }
}
<?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 class="com.pctf.beans.TestBeanA" name="testBeanA">
        <property name="name" value="测试BeanA"></property>
        <!--<property name="testBeanB" ref="testBeanB"></property>-->
        <constructor-arg value="testBeanB" index="0"></constructor-arg>
    </bean>

    <bean class="com.pctf.beans.TestBeanB" name="testBeanB">
        <property name="name" value="测试BeanB"></property>
        <!--<property name="testBeanA" ref="testBeanA"></property>-->
        <constructor-arg value="testBeanA" index="0"></constructor-arg>
    </bean>

</beans>
import com.pctf.beans.TestBeanA;
import com.pctf.beans.TestBeanB;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;

public class BeanLoadingTest {

    public static void main(String[] args) {
        BeanFactory bf = new XmlBeanFactory(new ClassPathResource("bean-loading-config.xml"));
        //((XmlBeanFactory) bf).setAllowCircularReferences(false);
        TestBeanA testBeanA = (TestBeanA) bf.getBean("testBeanA");
        TestBeanB testBeanB = bf.getBean(TestBeanB.class);
        System.out.println(testBeanA.getName());
        System.out.println(testBeanB.getName());
    }
}

上一篇下一篇

猜你喜欢

热点阅读