spring源码:bean标签的解析之创建BeanDefinition

本文详细解析了Spring框架中BeanDefinition的六种实现及其作用,包括AnnotatedGenericBeanDefinition、ChildBeanDefinition等。介绍了BeanDefinition在Spring配置文件中的角色及其实现类之间的关系,以及BeanDefinition的创建和属性赋值过程。

一、BeanDefinition介绍

BeanDefinition 是一个接口,在 Spring 中存在六种实现:

  • AnnotatedGenericBeanDefinition:注解bean
  • ChildBeanDefinition:子bean
  • ConfigurationClassBeanDefinitionReader.ConfigurationClassBeanDefinition
  • GenericBeanDefinition:spring2.5之后代替ChildBeanDefinition和RootBeanDefinition
  • RootBeanDefinition:父bean
  • ScannedGenericBeanDefinition:扫描bean
      BeanDefinition是配置文件<bean>元素标签在容器中的内部表示形式 。<bean>元素标签拥有class、scope、lazy-init等配置属性,AbstractBeanDefinition则提供了相应的beanClass、scope、lazyInit属性,BeanDefinition 和<bean>中的属性是一一对应的 。以上六种实现类都继承了AbstractBeanDefinition,其中 RootBeanDefinition 是最常用的实现类,它对应一般性的<bean>元素标签, GenericBeanDefinition 是自 2.5 版本以后新加入的 bean文件配置属性定义类,是一站式服务类。
      在配置文件中可以定义父<bean>和子<bean>,父<bean>用 RootBeanDefinition 表示,而子<bean>用 ChildBeanDefiniton 表示,而没有父<bean> 的<bean>就使用 RootBeanDefinition 表示 。AbstractBeanDefinition 对两者共同的类信息进行抽象。
      Spring 通过 BeanDefinition 将配置文件中的<bean>配置信息转换为容器的内部表示,并将
    这些 BeanDefiniton 注册到 BeanDefinitonRegistry 中 。 Spring 容器的 BeanDefinitionRegistry 就像
    是 Spring 配置信息的内存数据库
    ,主要是以 map 的形式保存,后续操作直接从 BeanDefinitionRegistry 中读取配置信息。

二、目的

  从上面BeanDefinition的介绍可以知道,xml中的bean标签对应spring中的一个BeanDefinition( 具体实现为GenericBeanDefinition)实例,bean标签的属性与BeanDefinition中的属性也是一一对应的。在给BeanDefinition的属性设置值时,首先要创建BeanDefinition。创建BeanDefinition的过程,就是我们要分析的重点。先来看下AbstractBeanDefinition类中包含的属性

public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor
		implements BeanDefinition, Cloneable {
	// 省略一些常量
	
	// bean的作用范围,对应bean标签中的scope属性
	@Nullable
	private String scope = SCOPE_DEFAULT;

	// 是否是原型,对应bean标签中的abstract属性
	private boolean abstractFlag = false;

	// 是否延迟加载,对应bean标签中的lazy-init属性
	private boolean lazyInit = false;

	// 自动注入模式,对应备案标签中的autowire属性
	private int autowireMode = AUTOWIRE_NO;

	// 依赖检查
	private int dependencyCheck = DEPENDENCY_CHECK_NONE;

	// 用来表示一个bean的实例化依靠另一个bean先实例化,对应bean标签的depend-on属性
	@Nullable
	private String[] dependsOn;

	private boolean autowireCandidate = true;

	// 自动装配时当出现多个bean候选者时,将作为首选者,对应bean标签的primary属性
	private boolean primary = false;

	// 用于记录Qualifier,对应子元素qualifier
	private final Map<String, AutowireCandidateQualifier> qualifiers = new LinkedHashMap<>(0);

	@Nullable
	private Supplier<?> instanceSupplier;

	// 允许访问非公开的构造器和方法,程序设置
	private boolean nonPublicAccessAllowed = true;

	// 是否以一种宽松的模式解析构造函数
	private boolean lenientConstructorResolution = true;

	// 对应bean标签中的factory-bean属性
	@Nullable
	private String factoryBeanName;

	// 对应bean标签中的factory-method属性
	@Nullable
	private String factoryMethodName;

	// 记录构造函数注入属性,对应bean标签的constructor-arg子元素
	@Nullable
	private ConstructorArgumentValues constructorArgumentValues;

	// 普通属性集合
	@Nullable
	private MutablePropertyValues propertyValues;

	// 方法重写的持有者,记录lookup-method、replace-method子元素
	@Nullable
	private MethodOverrides methodOverrides;

	// 初始化方法,对应bean标签中的init-method属性
	@Nullable
	private String initMethodName;

	// 销毁方法,对应bean标签中的destroy-method属性
	@Nullable
	private String destroyMethodName;

	// 是否执行init-method,程序设置
	private boolean enforceInitMethod = true;

	// 是否执行destroy-method,程序设置
	private boolean enforceDestroyMethod = true;

	// 是否是用户定义的而不是应用程序本身定义的,创建AOP时候为true,程序设置
	private boolean synthetic = false;

	private int role = BeanDefinition.ROLE_APPLICATION;

	// bean的描述信息
	@Nullable
	private String description;

	// 这个bean定义的资源
	@Nullable
	private Resource resource;
}

三、相关类

  • org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader:解析xml标签的入口
  • org.springframework.beans.factory.xml.BeanDefinitionParserDelegate:解析bean标签
  • org.springframework.beans.factory.support.BeanDefinitionReaderUtils:创建BeanDefinition

四、源码分析

  1. 根据标签的命名空间(namespace)和标签名称来选择对应的处理方法。

    1.1 根据命名空间,选择对应的处理方法

    	protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
    		if (delegate.isDefaultNamespace(root)) {
    			NodeList nl = root.getChildNodes();
    			for (int i = 0; i < nl.getLength(); i++) {
    				Node node = nl.item(i);
    				if (node instanceof Element) {
    					Element ele = (Element) node;
    					// 默认标签的命名空间为:http://www.springframework.org/schema/beans
    					if (delegate.isDefaultNamespace(ele)) {
    						// 解析默认标签
    						parseDefaultElement(ele, delegate);
    					}
    					else {
    						// 解析自定义标签
    						delegate.parseCustomElement(ele);
    					}
    				}
    			}
    		}
    		else {
    			delegate.parseCustomElement(root);
    		}
    	}
    

    spring在解析xml的时候,把标签分为两类:默认标签扩展标签
    默认标签

    <bean id="person1" class="com.kaka.spring.beans.Person"/>
    

    扩展标签

    <tx:annotaition-driven/>
    

    1.2 根据标签的名称,选择对应的处理方法

    	// 默认标签解析
    	private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
    		if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
    			// 对import标签的处理
    			importBeanDefinitionResource(ele);
    		}
    		else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
    			// 处理alias标签
    			processAliasRegistration(ele);
    		}
    		else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
    			// 处理bean标签(本章主要分析这个)
    			processBeanDefinition(ele, delegate);
    		}
    		else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
    			// 递归(recurse)处理beans标签
    			doRegisterBeanDefinitions(ele);
    		}
    	}
    
  2. 处理bean标签的大致步骤(还在DefaultBeanDefinitionDocumentReader这个类中)

	protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
		// 1.解析bean标签,获取bdHolder实例(本章主要分析这个)
		BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
		if (bdHolder != null) {
			// 2.装饰bdHolder
			bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
			try {
				// 3.注册装饰后的实例
				BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
			}
			catch (BeanDefinitionStoreException ex) {
				getReaderContext().error("Failed to register bean definition with name '" +
						bdHolder.getBeanName() + "'", ele, ex);
			}
			// 4.发布注册事件,通知相关监听器
			getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
		}
	}
  1. 交由BeanDefinitionParserDelegate这个类,去处理bean标签,最终获取一个BeanDefinitionHolder实例。
	public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
		return parseBeanDefinitionElement(ele, null);
	}

	public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
		// 解析id属性
		String id = ele.getAttribute(ID_ATTRIBUTE);
		// 解析name属性
		String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

		List<String> aliases = new ArrayList<>();
		if (StringUtils.hasLength(nameAttr)) {
			String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
			aliases.addAll(Arrays.asList(nameArr));
		}

		String beanName = id;
		if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
			beanName = aliases.remove(0);
			if (logger.isDebugEnabled()) {
				logger.debug("No XML 'id' specified - using '" + beanName +
						"' as bean name and " + aliases + " as aliases");
			}
		}

		if (containingBean == null) {
			checkNameUniqueness(beanName, aliases, ele);
		}
		// 解析bean标签的其他属性,并封装至beanDefinition。这儿就是本章分析的重点,点进去
		AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
		if (beanDefinition != null) {
			if (!StringUtils.hasText(beanName)) {
				try {
					if (containingBean != null) {
						beanName = BeanDefinitionReaderUtils.generateBeanName(
								beanDefinition, this.readerContext.getRegistry(), true);
					}
					else {
						beanName = this.readerContext.generateBeanName(beanDefinition);
						// Register an alias for the plain bean class name, if still possible,
						// if the generator returned the class name plus a suffix.
						// This is expected for Spring 1.2/2.0 backwards compatibility.
						String beanClassName = beanDefinition.getBeanClassName();
						if (beanClassName != null &&
								beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
								!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
							aliases.add(beanClassName);
						}
					}
					if (logger.isDebugEnabled()) {
						logger.debug("Neither XML 'id' nor 'name' specified - " +
								"using generated bean name [" + beanName + "]");
					}
				}
				catch (Exception ex) {
					error(ex.getMessage(), ele);
					return null;
				}
			}
			String[] aliasesArray = StringUtils.toStringArray(aliases);
			// 将获取到的信息封装到BeanDefinitionHolder实例中
			return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
		}

		return null;
	}
	
	//解析bean标签的其他属性 
	public AbstractBeanDefinition parseBeanDefinitionElement(
			Element ele, String beanName, @Nullable BeanDefinition containingBean) {

		this.parseState.push(new BeanEntry(beanName));

		// 解析class属性
		String className = null;
		if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
			className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
		}
		// 解析parent属性
		String parent = null;
		if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
			parent = ele.getAttribute(PARENT_ATTRIBUTE);
		}

		try {
			// 创建用于承载属性的 AbstractBeanDefinition 类型的 GenericBeanDefinition,点进去
			AbstractBeanDefinition bd = createBeanDefinition(className, parent);

			// 硬编码解析默认bean的各种属性
			parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
			// 提取 descripτion
			bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));

			// 解析元数据
			parseMetaElements(ele, bd);
			// 解析lookup-method 属性
			parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
			// 解析replaced-method 属性
			parseReplacedMethodSubElements(ele, bd.getMethodOverrides());

			// 解析构造函数参数
			parseConstructorArgElements(ele, bd);
			// 解析property子元素
			parsePropertyElements(ele, bd);
			// 解析qualifier子元素
			parseQualifierElements(ele, bd);

			bd.setResource(this.readerContext.getResource());
			bd.setSource(extractSource(ele));

			return bd;
		}
		catch (ClassNotFoundException ex) {
			error("Bean class [" + className + "] not found", ele, ex);
		}
		catch (NoClassDefFoundError err) {
			error("Class that bean class [" + className + "] depends on not found", ele, err);
		}
		catch (Throwable ex) {
			error("Unexpected failure during bean definition parsing", ele, ex);
		}
		finally {
			this.parseState.pop();
		}

		return null;
	}

	protected AbstractBeanDefinition createBeanDefinition(@Nullable String className, @Nullable String parentName)
			throws ClassNotFoundException {
		//  交由BeanDefinitionReaderUtils创建AbstractBeanDefinition 
		return BeanDefinitionReaderUtils.createBeanDefinition(
				parentName, className, this.readerContext.getBeanClassLoader());
	}

  1. 使用BeanDefinitionReaderUtils创建AbstractBeanDefinition
	public static AbstractBeanDefinition createBeanDefinition(
			@Nullable String parentName, @Nullable String className, @Nullable ClassLoader classLoader) throws ClassNotFoundException {
		// 创建GenericBeanDefinition
		GenericBeanDefinition bd = new GenericBeanDefinition();
		bd.setParentName(parentName);
		if (className != null) {
			if (classLoader != null) {
				// 如果classLoader不为空,则使用该classLoader加载该类对象,否则只记录className
				// ClassUtils中反射的类实例是缓存起来的,不是每次都反射获取
				bd.setBeanClass(ClassUtils.forName(className, classLoader));
			}
			else {
				bd.setBeanClassName(className);
			}
		}
		return bd;
	}

经过上面这个步骤,就创建出了一个GenericBeanDefinition实例,并给其parentName、beanClass和beanClassName三个属性设置了值。

五、总结

  1. DefaultBeanDefinitionDocumentReader根据标签的命名空间标签名称选择对应的处理方法,bean标签的整体处理过程是在DefaultBeanDefinitionDocumentReader#processBeanDefinition()方法中完成的。
  2. 处理bean标签的第一步,需要获取BeanDefinitionHolder实例,该实例由BeanDefinitionParserDelegate创建。
  3. BeanDefinitionHolder的创建需要包含一个BeanDefinition实例,这个BeanDefinition实例由BeanDefinitionReaderUtils创建
  4. BeanDefinition实例创建完成之后,其各个属性的赋值是由BeanDefinitionParserDelegate#parseBeanDefinitionElement()方法完成。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值