10Spring 源码学习 ~ Bean 的加载步骤详解

Posted 戴泽supp

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了10Spring 源码学习 ~ Bean 的加载步骤详解相关的知识,希望对你有一定的参考价值。

Bean 的加载步骤详解(一)

一、FactoryBean 的使用

一般情况下,Spring 通过反射机制,利用 bean 的 class 属性指定的实现类,来实例化 bean。但假如实例化的 bean 需要配置文件提供大量的信息,这个时候配置文件的灵活方式是受限的,此时采用编码的方式也许可得到一个简单的方案。Spring 为此提供了一个 FactoryBean 的工厂类接口,用户可以通过实现该接口,来定制实例化 bean 的逻辑。

Spring 本生提供了 70 多个 FactoryBean 的实现,而且从 Spring 3.0 开始,FactoryBean 可支持泛型,即接口声明改为 FactoryBean<T> 的形式。如下:

package org.springframework.beans.factory;

import org.springframework.lang.Nullable;

public interface FactoryBean<T> 

	String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";

    //返回由 FactoryBean 创建的 bean 实例,如果 isSingleton 返回 true,则该实例会放到 Spring 容器中的单例缓存池中
	@Nullable
	T getObject() throws Exception;

    //返回由 FactoryBean 创建的 bean 类型
	@Nullable
	Class<?> getObjectType();

    //返回 FactoryBean 创建的 bean 实例的作用域,默认是单例 singleton
	default boolean isSingleton() 
		return true;
	

<bean> 中的 class 属性是 FactoryBean 的实现类时,通过 getBean() 方法返回的不是 FactoryBean 本身,而是 FactoryBean#getObject 返回的对象。

示例:

Car.java

package com.luo.spring.guides.helloworld.beanloading.factorybean;

import lombok.Data;
import lombok.ToString;

/**
 * @author : archer
 * @date : Created in 2022/10/28 10:27
 * @description :
 */
@Data
@ToString
public class Car 

    //最大速度
    private int maxSpeed;
    //品牌
    private String brand;
    //价格
    private double price;

CarFactoryBean.java

package com.luo.spring.guides.helloworld.beanloading.factorybean;

import org.springframework.beans.factory.FactoryBean;

/**
 * @author : archer
 * @date : Created in 2022/10/28 10:28
 * @description :
 */
public class CarFactoryBean implements FactoryBean<Car> 

    private String carInfo;

    @Override
    public Car getObject() throws Exception 
        Car car = new Car();
        String[] infos = carInfo.split(",");
        car.setBrand(infos[0]);
        car.setMaxSpeed(Integer.parseInt(infos[1]));
        car.setPrice(Double.parseDouble(infos[2]));
        return car;
    

    @Override
    public Class<?> getObjectType() 
        return Car.class;
    

    @Override
    public boolean isSingleton() 
        return false;
    

    public String getCarInfo() 
        return carInfo;
    

    //接受逗号分隔符设置属性信息,并且顺序固定是 brand,maxSpeed,price
    public void setCarInfo(String carInfo) 
        this.carInfo = carInfo;
    

facotryBeanTest.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="car" class="com.luo.spring.guides.helloworld.beanloading.factorybean.CarFactoryBean">
        <property name="carInfo" value="超级跑车,400,2000000"/>
    </bean>

</beans>

Main.java

package com.luo.spring.guides.helloworld.beanloading.factorybean;

import com.luo.spring.guides.helloworld.common.TestBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author : archer
 * @date : Created in 2022/10/28 10:49
 * @description :
 */
public class Main 

    public static void main(String[] args) 
        ApplicationContext bf = new ClassPathXmlApplicationContext("beanloading/factorybean/facotryBeanTest.xml");

        //获取 Car 实例
        Car car = (Car) bf.getBean("car");
        System.out.println(car);

        //获取 CarFactoryBean 实例
        CarFactoryBean carFactoryBean = (CarFactoryBean) bf.getBean("&car");
        System.out.println(carFactoryBean.getClass());
    

输出:

Car(maxSpeed=400, brand=超级跑车, price=2000000.0)
class com.luo.spring.guides.helloworld.beanloading.factorybean.CarFactoryBean

二、缓存中获取单例 bean

单例 bean 的加载只会在 Spring 的容器中创建一次,后续再获取是直接从缓存中获取。这里首先是从缓存中加载,不存在再去 singleFactories 中加载。这里 Spring 为了避免循环,它创建 bean 的原则是不等 bean 创建完成,就会将创建 bean 的 ObjectFactory 提早曝光加入到缓存中,一旦下个 bean 创建时需要依赖上个 bean,则直接使用 ObjectFactory。

@Override
@Nullable
public Object getSingleton(String beanName) 
    //参数 true 表示允许早期依赖
    return getSingleton(beanName, true);


@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) 
    // Quick check for existing instance without full singleton lock
    //检查缓存中是否存在实例
    Object singletonObject = this.singletonObjects.get(beanName);
    //缓存还不存在单例 bean 并且当前正在创建中
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) 
        //判断早期依赖中是否存在实例,有则表示 bean 正在加载
        singletonObject = this.earlySingletonObjects.get(beanName);
        if (singletonObject == null && allowEarlyReference) 
            //不存在并且允许早期依赖,则锁定全局变量并进行处理
            synchronized (this.singletonObjects) 
                // Consistent creation of early reference within full singleton lock
                //双重判断缓存中是否存在实例,防止上层判断完后准备加锁的时候,另一线程已实例化,并放到缓存中了
                singletonObject = this.singletonObjects.get(beanName);
                if (singletonObject == null) 
                    singletonObject = this.earlySingletonObjects.get(beanName);
                    if (singletonObject == null) 
                        //当某些 bean 需要提前初始化的时候,则会调用 addSingleFactory 方法将对应的
                        //ObjectFactory 初始化策略,存储在 singletonFactories中
                        ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                        if (singletonFactory != null) 
                            //调用预先设定的 getObject 方法
                            singletonObject = singletonFactory.getObject();
                            //记录在缓存中,earlySingletonObjects 与 singletonFactories 互斥
                            this.earlySingletonObjects.put(beanName, singletonObject);
                            this.singletonFactories.remove(beanName);
                        
                    
                
            
        
    
    return singletonObject;


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);
        
    

名词解释:

  • **singletonObjects:**Map 结构,用于保存 BeanName 和创建 bean 实例之间的关系,beanName -> bean instance;
  • **singletonFactories:**Map 结构,用于保存 BeanName 和创建 bean 实例的工厂之间的关系,beanName -> ObjectFactory;
  • **earlySingletonObjects:**Map 结构,用于保存 BeanName 和创建 bean 实例之间的关系
    • 与 singletonObjects 不同之处在于,当一个单例 bean 被放到里面后,那么当 bean 还在创建过程中时,就可以通过 getBean 方法获取到了,其目的是用来检测循环引用。
  • **registeredSingletons:**Set 结构,用来保存当前所有已注册的单例 beanName;

上述代码大致步骤如下:

  • 1、首先尝试从 singletonObjects 中获取实例
  • 2、若上面获取不到,再尝试从 earlySingletonObjects 中获取实例
  • 3、若还是获取不到并且 allowEarlyReference 为 true (允许循环引用)时,再从 singletonFactories 中获取对应的 ObjectFactory,在调用这个 ObjectFactory 的 getObject 来创建 bean,并放到 earlySingletonObjects 缓存中去,并从 singletonFactories 中 remove 掉这个 ObjectFactory。

三、从 bean 的实例中获取对象

在 getBean 的方法中,getObjectForBeanInstance 是个高频率使用的方法。无论是从缓存中还是根据不同的 scope 策略得到 bean 实例后,首先做的都是调这个方法来检测下正确性,即当前 bean 是否是 FactoryBean 类型的 bean,如果是,则调用对应的 FactoryBean 实例中的 getObject() 作为返回值。

这里返回的只是 bean 最原始的状态。并不一定是我们真正需要的 bean。

如:假如我们需要对工厂 bean 进行处理,这里得到的是工厂 bean 的初始状态,而我们真正需要的是工厂 bean 中定义的 factory-method 方法中返回的 bean。而 getObjectForBeanInstance 就是完成这个工作的。源码如下:

protected Object getObjectForBeanInstance(
    Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) 

    // Don't let calling code try to dereference the factory if the bean isn't a factory.
    //如果指定的 name 是工厂相关(以 & 为前缀),则进入代码
    if (BeanFactoryUtils.isFactoryDereference(name)) 
        if (beanInstance instanceof NullBean) 
            return beanInstance;
        
        //beanInstance 不是 FactoryBean 类型,则验证不通过
        if (!(beanInstance instanceof FactoryBean)) 
            throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
        
        if (mbd != null) 
            mbd.isFactoryBean = true;
        
        //getBean("&car"); 直接返回 FactoryBean
        return beanInstance;
    

    // Now we have the bean instance, which may be a normal bean or a FactoryBean.
    // If it's a FactoryBean, we use it to create a bean instance, unless the
    // caller actually wants a reference to the factory.
    //现在这个 beanInstance 可能是普通的 bean 实例或者 FactoryBean 对象,
    //如果是普通的 bean,则直接返回
    if (!(beanInstance instanceof FactoryBean)) 
        return beanInstance;
    

    //加载 FactoryBean
    Object object = null;
    if (mbd != null) 
        mbd.isFactoryBean = true;
    
    else 
        //尝试从缓存中加载 bean
        object = getCachedObjectForFactoryBean(beanName);
    
    if (object == null) 
        // Return bean instance from factory.
        //到这里已经明确知道 beanInstance 一定是 FactoryBean 类型
        FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
        // Caches object obtained from FactoryBean if it is a singleton.
        //containsBeanDefinition 检测 beanDefinitionMap (即所有已加载的类)中检测是否定义了 beanName
        if (mbd == null && containsBeanDefinition(beanName)) 
            //将存储 XML 配置文件的 GernericBeanDefinition 转换为 RootBeanDefinition,
            //如果指定 beanName 是子 Bean 的话,同时会合并父类的相关属性
            mbd = getMergedLocalBeanDefinition(beanName);
        
        //是否是用户定义的,而不是程序本身定义的
        boolean synthetic = (mbd != null && mbd.isSynthetic());
        //用户自定义的无需后置处理
        object = getObjectFromFactoryBean(factory, beanName, !synthetic);
    
    return object;

上述中主要是做一些功能性的判断检查,大致如下:

  • 1、验证 FactoryBean 的正确性
  • 2、非 FactoryBean 不做任何处理
  • 3、对 bean 进行转换
  • 4、将从 Factory 中解析 bean 的工作委托给 getObjectFromFactoryBean。

即真正核心代码委托给了 getObjectFromFactoryBean,其源码如下:

//shouldPostProcess 为 true,表示需要后置处理
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) 
    //如果是单例模式
    if (factory.isSingleton() && containsSingleton(beanName)) 
        synchronized (getSingletonMutex()) 
            Object object = this.factoryBeanObjectCache.get(beanName);
            if (object == null) 
                object = doGetObjectFromFactoryBean(factory, beanName);
                // Only post-process and store if not put there already during getObject() call above
                // (e.g. because of circular reference processing triggered by custom getBean calls)
                Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
                if (alreadyThere != null) 
                    object = alreadyThere;
                
                else 
                    if (shouldPostProcess) 
                        if (isSingletonCurrentlyInCreation(beanName)) 
                            // Temporarily return non-post-processed object, not storing it yet..
                            return object;
                        
                        beforeSingletonCreation(beanName);
                        try 
                            //调用 ObjectFactory 的后处理器
                            object = postProcessObjectFromFactoryBean(object, beanName);
                        
                        catch (Throwable ex) 
                            throw new BeanCreationException(beanName,
                                                            "Post-processing of FactoryBean's singleton object failed", ex);
                        
                        finally 
                            afterSingletonCreation(beanName);
                        
                    
                    if (containsSingleton(beanName)) 
                        this.factoryBeanObjectCache.put(beanName, object);
                    
                
            
            return object;
        
    
    else 
        Object object = doGetObjectFromFactoryBean(factory, beanName);
        if (shouldPostProcess) 
            try 
                //调用 ObjectFactory 的后处理器
                object = postProcessObjectFromFactoryBean(object, beanName);
            
            catch (Throwable ex) 
                throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
            
        
        return object;
    

这个方法里的逻辑就是,保证返回的 bean,如果是单例的,就是全局唯一的,同时加了一些缓存以提高性能,而获取真正实例对象的逻辑在 doGetObjectFromFactoryBean 方法中,当 bean 声明为 FactoryBean 类型时,提取 bean 时,提取的并不是 FactoryBean,而是 FactoryBean 中对应的 getObject 方法返回的 bean,doGetObjectFromFactoryBean 正是实现这个功能的,doGetObjectFromFactoryBean 源码如下:

private Object doGetObjectFromFactoryBean(FactoryBean<?> factory, String beanName) throws BeanCreationException 
    Object object;
    try 
        //需要权限验证
        if (System.getSecurityManager() != null) 
            AccessControlContext acc = getAccessControlContext();
            try 
                object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc);
            
            catch (PrivilegedActionException pae) 
                throw pae.getException();
            
        
        else 
            //直接调用 getObject 方法返回
            object = factory.getObject();
        
    
    catch (FactoryBeanNotInitializedException ex) 
        throw new BeanCurrentlyInCreationException(beanName, ex.toString());
    
    catch (Throwable ex) 
        throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
    

    // Do not accept a null value for a FactoryBean that's not fully
    // initialized yet: Many FactoryBeans just return null then.
    if (object == null) 
        if (isSingletonCurrentlyInCreation(beanName)) 
            throw new BeanCurrentlyInCreationException(
                beanName, "FactoryBean which is currently in creation returned null from getObject");
        
        object = new NullBean();
    
    return object;

处理完 doGetObjectFromFactoryBean 之后,程序还做了一些后置处理,即 shouldPostProcess 为 true 时的逻辑,先看 AbstractAutowireCapableBeanFactory#postProcessObjectFromFactoryBean,源码如下:

@Override
protected Object postProcessObjectFromFactoryBean(Object object, String beanName) 
    return applyBeanPostProcessorsAfterInitialization(object, beanName);


@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
    throws BeansException 

    Object result = existingBean;
    for (BeanPostProcessor processor : getBeanPostProcessors()) 
        Object current = processor.postProcessAfterInitialization(result, beanName);
        if (current Spring源码学习bean的加载

9Spring 源码学习 ~ Bean 的加载

Spring源码学习笔记——Bean加载

Spring源码学习~11Bean 的加载步骤详解

Spring源码学习~11Bean 的加载步骤详解

520就应该和女朋友一起学习Spring源码——Bean加载