Spring原理学习系列之六:IOC原理之BeanDefinition注册

引言

在上一篇文章中,我们大致介绍了Bean创建、Bean加载的流程,但是由于文章篇幅所限,不能事无巨细的进行详细介绍。后续本系列的文章将对这部分的内容进行庖丁解牛,尽可能的将IOC中比较重要的细节说明清楚,以便于自己以及花时间阅读本文的读者可以加深对于Spring IOC的深入理解。

  • BeanDefinition
  • BeanDefinitionRegistry
  • 总结

一、BeanDefinition

纳尼,你还要说Spring IOC,之前的文章你还没有说够嘛?
在这里插入图片描述
谁让Spring中关于IOC这部分的内容这么多呢,前面的文章还没有说的很细。所以只能继续慢慢往下唠叨了。废话不多说,我们来继续IOC

BeanDefinition是用来描述Spring中的Bean,是包装Bean的数据结构。其源码如下所示:

public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {

	
	//标准单例作用域的作用域标识符:“singleton”,对于扩展的bean工厂可能支持更多的作用域
	String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;

	//标准原型作用域的范围标识符:“prototype”
	String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;


	//表示BeanDefinition是应用程序主要部分的角色提示,通常对应于用户定义的bean
	int ROLE_APPLICATION = 0;

	//表示BeanDefinition是某些大型配置的支持部分的角色提示,通常是一个外部ComponentDefinition。
	//当查看某个特定的ComponentDefinition时,认为bean非常重要,
	//以便在查看应用程序的整体配置时能够意识到这一点
	int ROLE_SUPPORT = 1;

	//角色提示表明一个BeanDefinition是提供一个完全背景的角色,并且与最终用户没有关系。
	//这个提示用于注册完全是ComponentDefinition内部工作的一部分的bean
	int ROLE_INFRASTRUCTURE = 2;

	//1、当前Bean父类名称
	//如果父类存在,设置这个bean定义的父定义的名称
	void setParentName(@Nullable String parentName);

	//如果父类存在,则返回当前Bean的父类的名称
	@Nullable
	String getParentName();

	//2、当前Bean的className
	//指定此bean定义的bean类名称。
	//类名称可以在bean factory后期处理中修改,通常用它的解析变体替换原来的类名称
	void setBeanClassName(@Nullable String beanClassName);

	//返回此bean定义的当前bean类名称
	//需要注意的是,这不一定是在运行时使用的实际类名,以防子类定义覆盖/继承其父类的类名
	//此外,这可能只是调用工厂方法的类,或者它 在调用方法的工厂bean引用的情况下甚至可能是空的
	//因此,不要认为这是在运行时定义的bean类型,而只是将其用于在单独的bean定义级别进行解析
	@Nullable
	String getBeanClassName();

	//3、bean作用域
	//覆盖此bean的目标范围,指定一个新的范围名称
	void setScope(@Nullable String scope);

	//返回此bean的当前目标作用域的名称,如果没有确定,返回null
	@Nullable
	String getScope();

	//懒加载
	//设置这个bean是否应该被延迟初始化。如果{false},那么这个bean将在启动时由bean工厂实例化,
	//这些工厂执行单例的立即初始化。
	//懒加载 <bean lazy-init="true/false">
	void setLazyInit(boolean lazyInit);

	//返回这个bean是否应该被延迟初始化,即不是在启动时立即实例化。只适用于单例bean。
	boolean isLazyInit();

	//5.依赖关系设置
	//设置这个bean依赖被初始化的bean的名字。 bean工厂将保证这些bean首先被初始化。
	//<bean depends-on="">
	void setDependsOn(@Nullable String... dependsOn);

	//返回这个bean依赖的bean名称
	@Nullable
	String[] getDependsOn();

	//6.是否是自动转配设置
	//设置这个bean是否是获得自动装配到其他bean的候选人。
	//需要注意是,此标志旨在仅影响基于类型的自动装配。
	//它不会影响按名称的显式引用,即使指定的bean没有标记为autowire候选,也可以解决这个问题。
	//因此,如果名称匹配,通过名称的自动装配将注入一个bean。
	void setAutowireCandidate(boolean autowireCandidate);

	//返回这个bean是否是自动装配到其他bean的候选者。就是是否在其他类中使用autowired来注入当前Bean的
	//是否为被自动装配 <bean autowire-candidate="true/false">
	boolean isAutowireCandidate();

	//7.主候选Bean
	//是否为主候选bean    使用注解:@Primary
	
	void setPrimary(boolean primary);
	
	//返回这个bean是否是主要的autowire候选者
	boolean isPrimary();

	//8.定义创建该Bean对象的工厂类
	//指定要使用的工厂bean(如果有的话), 这是调用指定的工厂方法的bean的名称
	void setFactoryBeanName(@Nullable String factoryBeanName);

	//如果有返回工厂bean的名字
	@Nullable
	String getFactoryBeanName();

	//9.创建该Bean对象的工厂方法
	//如果有,指定工厂方法。这个方法先将通过构造函数参数被调用,或者如果参数,将调用该方法的无参数构造
	void setFactoryMethodName(@Nullable String factoryMethodName);
	//如果存在,返回工厂方法名
	@Nullable
	String getFactoryMethodName();

	//10.返回此bean的构造函数参数值
	//返回此bean的构造函数参数值
	ConstructorArgumentValues getConstructorArgumentValues();

	default boolean hasConstructorArgumentValues() {
		return !getConstructorArgumentValues().isEmpty();
	}

	//11.获取属性
	MutablePropertyValues getPropertyValues();

	default boolean hasPropertyValues() {
		return !getPropertyValues().isEmpty();
	}

	//12.设置初始方法
	void setInitMethodName(@Nullable String initMethodName);

	@Nullable
	String getInitMethodName();


	void setDestroyMethodName(@Nullable String destroyMethodName);

	@Nullable
	String getDestroyMethodName();


	void setRole(int role);

	//13.当前Bean的角色
	//获取这个bean的角色
	int getRole();

	void setDescription(@Nullable String description);

	//14.可读描述
	//返回对bean定义的可读描述
	@Nullable
	String getDescription();

	//返回该bean定义来自的资源的描述
	@Nullable
	String getResourceDescription();

	//返回原始的BeanDefinition;如果没有,则返回null。允许检索装饰的bean定义
	@Nullable
	BeanDefinition getOriginatingBeanDefinition();
	
	//15.当前Bean的基本特性
	//是否是单例的
	boolean isSingleton();

	//是否是多例的
	boolean isPrototype();

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

	

}

从上面的属性和方法分析可以看出,BeanDefinition对于一个Bean的描述做了比较完整的一套约束。这为后续的实现类提供了最基本的职责和属性。BeanDefinition只是一个接口,它的具体实现如下所示:
在这里插入图片描述

二、BeanDefinitionRegistry

BeanDefinitionRegistry 继承了 AliasRegistry 接口,其核心子类有三个:SimpleBeanDefinitionRegistryDefaultListableBeanFactory以及GenericApplicationContext,类机构图如下所示:
在这里插入图片描述
AliasRegistry 作为 BeanDefinitionRegistry 的顶层接口,它的作用主要为别名管理的通用型接口, AliasRegistry 定义了一些别名管理的方法。

public interface AliasRegistry {

	
	void registerAlias(String name, String alias);

	
	void removeAlias(String alias);

	
	boolean isAlias(String name);


	String[] getAliases(String name);

}

BeanDefinitionRegistry 接口在实现AliasRegistry之外还定义了关于 BeanDefinition 注册、注销、查询等一系列的操作。

public interface BeanDefinitionRegistry extends AliasRegistry {

	// 向注册表中注册一个新的 BeanDefinition 实例
	void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException;

	 // 移除注册表中已注册的 BeanDefinition 实例
	void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;

	 // 从注册中取得指定的 BeanDefinition 实例
	BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;

	 // 判断 BeanDefinition 实例是否在注册表中(是否注册)
	boolean containsBeanDefinition(String beanName);

	// 取得注册表中所有 BeanDefinition 实例的 beanName(标识)
	String[] getBeanDefinitionNames();

	// 返回注册表中 BeanDefinition 实例的数量
	int getBeanDefinitionCount();

	// beanName(标识)是否被占用
	boolean isBeanNameInUse(String beanName);

}

我们可以看下BeanDefinitionRegistry的类实现结构如下所示:

在这里插入图片描述
这里关注下实现类GenericApplicationContext,其中比较重要的方法为registerBeanDefinition,它完成了BeanDefinition的注册 :

public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {

	private final DefaultListableBeanFactory beanFactory;
	
	...
	
	@Override
	public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException {

		this.beanFactory.registerBeanDefinition(beanName, beanDefinition);
	}
	...
}

注册过程实际是通过DefaultListableBeanFactoryregisterBeanDefinition来完成注册动作:

@Override
	public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException {

		Assert.hasText(beanName, "Bean name must not be empty");
		Assert.notNull(beanDefinition, "BeanDefinition must not be null");

		if (beanDefinition instanceof AbstractBeanDefinition) {
			try {
				((AbstractBeanDefinition) beanDefinition).validate();
			}
			catch (BeanDefinitionValidationException ex) {
				throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
						"Validation of bean definition failed", ex);
			}
		}

		BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
		if (existingDefinition != null) {
			if (!isAllowBeanDefinitionOverriding()) {
				throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
			}
			else if (existingDefinition.getRole() < beanDefinition.getRole()) {
				// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
				if (logger.isInfoEnabled()) {
					logger.info("Overriding user-defined bean definition for bean '" + beanName +
							"' with a framework-generated bean definition: replacing [" +
							existingDefinition + "] with [" + beanDefinition + "]");
				}
			}
			else if (!beanDefinition.equals(existingDefinition)) {
				if (logger.isDebugEnabled()) {
					logger.debug("Overriding bean definition for bean '" + beanName +
							"' with a different definition: replacing [" + existingDefinition +
							"] with [" + beanDefinition + "]");
				}
			}
			else {
				if (logger.isTraceEnabled()) {
					logger.trace("Overriding bean definition for bean '" + beanName +
							"' with an equivalent definition: replacing [" + existingDefinition +
							"] with [" + beanDefinition + "]");
				}
			}
			this.beanDefinitionMap.put(beanName, beanDefinition);
		}
		else {
			if (hasBeanCreationStarted()) {
				// Cannot modify startup-time collection elements anymore (for stable iteration)
				synchronized (this.beanDefinitionMap) {
					this.beanDefinitionMap.put(beanName, beanDefinition);
					List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
					updatedDefinitions.addAll(this.beanDefinitionNames);
					updatedDefinitions.add(beanName);
					this.beanDefinitionNames = updatedDefinitions;
					if (this.manualSingletonNames.contains(beanName)) {
						Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
						updatedSingletons.remove(beanName);
						this.manualSingletonNames = updatedSingletons;
					}
				}
			}
			else {
				// Still in startup registration phase
				this.beanDefinitionMap.put(beanName, beanDefinition);
				this.beanDefinitionNames.add(beanName);
				this.manualSingletonNames.remove(beanName);
			}
			this.frozenBeanDefinitionNames = null;
		}

		if (existingDefinition != null || containsSingleton(beanName)) {
			resetBeanDefinition(beanName);
		}
	}

其实上面这么多代码最重要的就是:

private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

this.beanDefinitionMap.put(beanName, beanDefinition);

三、总结

本文主要介绍了BeanDefinition以及BeanDefinition的注册,BeanDefinitionSpring处理Bean的统一的数据结构,BeanDefinitionRegistry的实现类对BeanDefinition完成了注册操作,注册最终结果保存在beanDefinitionMap这个ConcurrentHashMap中。今天的内容就到这里了,我们下次再会了哦。
在这里插入图片描述

发布了88 篇原创文章 · 获赞 49 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/Diamond_Tao/article/details/103484170