02-IOC之开启Bean的加载概览

1. 前言

       在上一篇博客中,我们介绍到了IOC容器初始化的过程中,会将BeanName以及BeanDefinition保存到IOC的容器中,此时并没有进行Bean的加载,而是在通过调用getBean()时才会进行加载(如果没有设置过lazyinit属性),而Bean的加载是基于BeanDefiniton进行加载的,那么BeanDefiniton是什么?

       通过名字可以知道,其是Bean的定义信息,代码如下:

public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {

	// 单例/原型的 Bean
	String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
	String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;


	// Bean 代表的角色是
	int ROLE_APPLICATION = 0;
	int ROLE_SUPPORT = 1;
	int ROLE_INFRASTRUCTURE = 2;

	// 设置/返回父 BeanDefinition 的名字
	void setParentName(@Nullable String parentName);
	String getParentName();

	// 设置/返回 BeanClassName
	void setBeanClassName(@Nullable String beanClassName);
	String getBeanClassName();

	// 设置/返回命名空间
	void setScope(@Nullable String scope);
	String getScope();

	// 设置懒加载
	void setLazyInit(boolean lazyInit);
	// 是否是懒加载
	boolean isLazyInit();

	/**
	 * 设置该 Bean 依赖的BeanName。
	 * BeanFactory将优先初始化依赖的Bean
	 */
	void setDependsOn(@Nullable String... dependsOn);

	// 返回依赖的 Bean的BeanName
	String[] getDependsOn();

	// 设置该 Bean 是否可以自动注入
	void setAutowireCandidate(boolean autowireCandidate);

	// 返回该 Bean 是否可以自动注入
	boolean isAutowireCandidate();

	// 设置该Bean是否是优先进行注入的Bean
	void setPrimary(boolean primary);

	// 返回该Bean是否是优先进行注入的Bean
	boolean isPrimary();

	// 设置 BeanFactory 的 Name
	void setFactoryBeanName(@Nullable String factoryBeanName);

	// 返回 BeanFactory 的 Name
	String getFactoryBeanName();

	// 设置工厂方法的名称
	void setFactoryMethodName(@Nullable String factoryMethodName);

	// 返回工厂方法的名称
	String getFactoryMethodName();

	// 返回该 Bean 构造函数的参数值
	ConstructorArgumentValues getConstructorArgumentValues();

	// 返回该 Bean 是否有构造函数的参数值
	default boolean hasConstructorArgumentValues() {
		return !getConstructorArgumentValues().isEmpty();
	}

	// 获取该 Bean 要被注入的属性值
	MutablePropertyValues getPropertyValues();

	//获取该 Bean 是否有要被注入的属性值
	default boolean hasPropertyValues() {
		return !getPropertyValues().isEmpty();
	}

	// 设置/返回初始化方法的名字
	void setInitMethodName(@Nullable String initMethodName);
	String getInitMethodName();

	// 设置/返回 Bean 销毁时方法的名字
	void setDestroyMethodName(@Nullable String destroyMethodName);
	String getDestroyMethodName();

	// 设置/返回为 Bean 设置的角色
	void setRole(int role);
	int getRole();

	// 设置/返回为 Bean 设置的描述
	void setDescription(@Nullable String description);
	String getDescription();

	// 返回此bean定义的可解析类型, 
	ResolvableType getResolvableType();

	// 是否是单例
	boolean isSingleton();

	// 是否是原型
	boolean isPrototype();

	// 是否是抽象类
	boolean isAbstract();

	// 返回此bean定义的资源的描述
	String getResourceDescription();

	// 返回 BeanDefinition
	BeanDefinition getOriginatingBeanDefinition();
}

       可以看到,xml文件中定义的属性都可以被映射到BeanDefinition中,而我们正是由于BeanDefinition可以按照我们在xml文件中的意愿进行初始化工作。

2. 简介

在这里插入图片描述
       Spring IOC容器所起的作用如上图所示,它会以某种方式加载 Configuration Metadata,将其解析注册到容器内部,然后会根据这些信息绑定整个系统的对象,最终组装成一个可用的基于轻量级容器的应用系统。

       Spring 在实现上述功能中,将整个流程分为两个阶段:容器初始化阶段和加载Bean 阶段。

       1、容器初始化阶段:首先通过某种方式加载 Configuration Metadata (主要是依据 ResourceResourceLoader 两个体系),然后容器会对加载的 Configuration MetaData
进行解析和分析,并将分析的信息组装成 BeanDefinition,并将其保存注册到相应的BeanDefinitionRegistry
中。至此,Spring IOC 的初始化工作完成。

       2、加载 bean 阶段:经过容器初始化阶段后,应用程序中定义的 Bean 信息已经全部加载到系统中了,当我们显示或者隐式地调用 getBean() 时,则会触发加载Bean阶段。在这阶段,容器会首先检查所请求的对象是否已经初始化完成了,如果没有,则会根据注册的 Bean 信息实例化请求的对象,并为其注册依赖,然后将其返回给请求方。至此第二个阶段也已经完成。

       当我们显示或者隐式地调用 getBean() 时,则会触发加载 Bean 阶段。如下:

public Object getBean(String name) throws BeansException {
    return doGetBean(name, null, null, false);
}

       内部调用 doGetBean()

  • name:要获取 Bean 的名字
  • requiredType:要获取 Bean 的类型
  • args:创建 Bean 时传递的参数。这个参数仅限于创建 Bean 时使用
  • typeCheckOnly:是否为类型检查
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
                          @Nullable final Object[] args, boolean typeCheckOnly) 
    throws BeansException {
    // 获取 beanName,这里是一个转换动作,将 name 转换为 beanName
    final String beanName = transformedBeanName(name);
    Object bean;

    // 从缓存中或者实例工厂中获取 bean
    // *** 这里会涉及到解决循环依赖 bean 的问题
    Object sharedInstance = getSingleton(beanName);
    if (sharedInstance != null && args == null) {
        if (logger.isDebugEnabled()) {
            if (isSingletonCurrentlyInCreation(beanName)) {
                logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
                             "' that is not fully initialized yet - a consequence of a circular reference");
            }
            else {
                logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
            }
        }
        bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    }

    else {

        // 因为 Spring 只解决单例模式下得循环依赖,在原型模式下如果存在循环依赖则会抛出异常
        if (isPrototypeCurrentlyInCreation(beanName)) {
            throw new BeanCurrentlyInCreationException(beanName);
        }

        // 如果容器中没有找到,则从父类容器中加载
        BeanFactory parentBeanFactory = getParentBeanFactory();
        if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
            String nameToLookup = originalBeanName(name);
            if (parentBeanFactory instanceof AbstractBeanFactory) {
                return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
                    nameToLookup, requiredType, args, typeCheckOnly);
            }
            else if (args != null) {
                return (T) parentBeanFactory.getBean(nameToLookup, args);
            }
            else {
                return parentBeanFactory.getBean(nameToLookup, requiredType);
            }
        }

        // 如果不是仅仅做类型检查则是创建bean,这里需要记录
        if (!typeCheckOnly) {
            markBeanAsCreated(beanName);
        }

        try {
            // 从容器中获取 beanName 相应的 GenericBeanDefinition,并将其转换为 		
            //	RootBeanDefinition
            final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);

            // 检查给定的合并的 BeanDefinition
            checkMergedBeanDefinition(mbd, beanName, args);

            // 处理所依赖的 bean
            String[] dependsOn = mbd.getDependsOn();
            if (dependsOn != null) {
                for (String dep : dependsOn) {
                    // 若给定的依赖 bean 已经注册为依赖给定的bean
                    // 循环依赖的情况
                    if (isDependent(beanName, dep)) {
                        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                                        "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
                    }
                    // 缓存依赖调用
                    registerDependentBean(dep, beanName);
                    try {
                        getBean(dep);
                    }
                    catch (NoSuchBeanDefinitionException ex) {
                        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                                        "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
                    }
                }
            }

            // bean 实例化
            // 单例模式
            if (mbd.isSingleton()) {
                sharedInstance = getSingleton(beanName, () -> {
                    try {
                        return createBean(beanName, mbd, args);
                    }
                    catch (BeansException ex) {
                        // 显示从单利缓存中删除 bean 实例
                        // 因为单例模式下为了解决循环依赖,可能他已经存在了,所以销毁它
                        destroySingleton(beanName);
                        throw ex;
                    }
                });
                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 {
                // 从指定的 scope 下创建 bean
                String scopeName = mbd.getScope();
                final 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, () -> {
                        beforePrototypeCreation(beanName);
                        try {
                            return createBean(beanName, mbd, args);
                        }
                        finally {
                            afterPrototypeCreation(beanName);
                        }
                    });
                    bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
                }
                catch (IllegalStateException ex) {
                    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",
                                                    ex);
                }
            }
        }
        catch (BeansException ex) {
            cleanupAfterBeanCreationFailure(beanName);
            throw ex;
        }
    }

    // 检查需要的类型是否符合 bean 的实际类型
    if (requiredType != null && !requiredType.isInstance(bean)) {
        try {
            T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
            if (convertedBean == null) {
                throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
            }
            return convertedBean;
        }
        catch (TypeMismatchException ex) {
            if (logger.isDebugEnabled()) {
                logger.debug("Failed to convert bean '" + name + "' to required type '" +
                             ClassUtils.getQualifiedName(requiredType) + "'", ex);
            }
            throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
        }
    }
    return (T) bean;
}

3. 获取 beanName

final String beanName = transformedBeanName(name);

       这里传递的是name,不一定就是 beanName(即id),可能是 aliasName,也有可能是 FactoryBean,所以这里需要调用 transformedBeanName() 方法对 name 进行一番转换,主要如下:

protected String transformedBeanName(String name) {
    return canonicalName(BeanFactoryUtils.transformedBeanName(name));
}

// 去除 FactoryBean 的修饰符
public static String transformedBeanName(String name) {
    Assert.notNull(name, "'name' must not be null");
    String beanName = name;
    // 如果 beanName 是以 & 开头,则说明是 FactoryBean
    while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
    	// 去除 &
        beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
    }
    return beanName;
}

// 转换 aliasName
public String canonicalName(String name) {
    String canonicalName = name;
    // Handle aliasing...
    String resolvedName;
    do {
    	// 返回别名对应的 BeanName
        resolvedName = this.aliasMap.get(canonicalName);
        if (resolvedName != null) {
            canonicalName = resolvedName;
        }
    }
    while (resolvedName != null);
    return canonicalName;
}

       主要处理过程包括两步:

  1. 去除 FactoryBean 的修饰符。如果 name 以 “&” 为前缀,那么会去掉该 “&”,例如,name = "&studentService",则会是 name = "studentService"
  2. 取指定的 alias 所表示的最终beanName。主要是一个循环获取beanName的过程,例如别名 A 指向名称为Bbean 则返回 B,若别名 A指向别名B,别名B指向名称为Cbean,则返回C

4. 从单例 bean 缓存中获取 bean

Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
    if (logger.isDebugEnabled()) {
        if (isSingletonCurrentlyInCreation(beanName)) {
            logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
                         "' that is not fully initialized yet - a consequence of a circular reference");
        }
        else {
            logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
        }
    }
    bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
	public Object getSingleton(String beanName) {
		return getSingleton(beanName, true);
	}

	private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		// 从 map 缓存中获取 BeanName 对应的单实例Bean
		Object singletonObject = this.singletonObjects.get(beanName);
		// 如果获取不到实例,并且当前不在创建该实例
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
				// 从 earlySingletonObjects 获取
				singletonObject = this.earlySingletonObjects.get(beanName);
				// 如果 earlySingletonObjects 获取不到,则从单例的工厂中去获取
				if (singletonObject == null && allowEarlyReference) {
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
						singletonObject = singletonFactory.getObject();
						// 保存到 earlySingletonObjects 中
						this.earlySingletonObjects.put(beanName, singletonObject);
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}

       我们知道单例模式的 bean 在整个过程中只会被创建一次,第一次创建后会将该 bean 加载到缓存中,后面在获取 bean 就会直接从单例缓存中获取。

       如果从缓存中得到了 bean,则需要调用 getObjectForBeanInstance()bean 进行实例化处理,因为缓存中记录的是最原始的 bean 状态,我们得到的不一定是我们最终想要的 bean

5. 原型模式依赖检查与 parentBeanFactory

if (isPrototypeCurrentlyInCreation(beanName)) {
    throw new BeanCurrentlyInCreationException(beanName);
}

// Check if bean definition exists in this factory.
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 {
        // No args -> delegate to standard getBean method.
        return parentBeanFactory.getBean(nameToLookup, requiredType);
    }
}

       Spring 只处理单例模式下得循环依赖,对于原型模式的循环依赖直接抛出异常

       主要原因还是在于Spring 解决循环依赖的策略有关。对於单例模式Spring 在创建 bean 的时候并不是等 bean 完全创建完成后才会将 bean添加至缓存中,而是不等bean创建完成就会将创建beanObjectFactory 提早加入到缓存中,这样一旦下一个 bean 创建的时候需要依赖 bean 时则直接使用 ObjectFactroy

       但是原型模式我们知道是没法使用缓存的,所以 Spring 对原型模式的循环依赖处理策略则是不处理。

       如果容器缓存中没有相对应的 BeanDefinition则会尝试从父类工厂(parentBeanFactory)中加载,然后再去递归调用 getBean()

5.1 依赖处理

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);
        try {
            getBean(dep);
        }
        catch (NoSuchBeanDefinitionException ex) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                            "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
        }
    }
}

       每个 Bean 都不是单独工作的,它会依赖其他 Bean,其他 Bean 也会依赖它,对于依赖的 Bean,它会优先加载,所以在 Spring 的加载顺序中,在初始化某一个 bean 的时候首先会初始化这个 bean 的依赖

5.2 作用域处理

       Spring bean 的作用域默认为 singleton,当然还有其他作用域,如prototyperequestsession 等,不同的作用域会有不同的初始化策略。

       在调用方法时,有一个 requiredType 参数,该参数的功能就是将返回的 bean 转换为 requiredType 类型。当然就一般而言我们是不需要进行类型转换的,也就是requiredType 为空(比如 ),但有可能会存在这种情况,比如我们返回的 bean 类型为 String,我们在使用的时候需要将其转换为 Integer,那么这个时候 requiredType 就有用武之地了。当然我们一般是不需要这样做的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章