Spring源码解析十一

上一篇中,我们了解到Spring单独创建了GenericBeanDefinition对象来存储Bean标签解析出的属性值。在分析这个源码之前,我们有必要来了解下GenericBeanDefinition这个类。
要了解GenericBeanDefinition 这个对象,我们还需要从BeanDefinition对象开始:
在这里插入图片描述
可以看到,BeanDefinition 就是一个接口。我们之前讲过在Spring中,每个bean在Spring容器中都是以BeanDefinition的形式存的,而且BeanDefinition的设计就是为了存放bean的信息的。我 们先看下BeanDefinition类的继承图:
在这里插入图片描述
可以看到,直接实现BeanDefinition接口的为抽象类AbstractBeanDefinition,而继承抽象类AbstractBeanDefinition的有三个类,分是RootBeanDefinition、ChildBeanDefinition、GenericBeanDefinition,我们在前面介绍的就是GenericBeanDefinition。
Spring之前的版本,bean标签解析后在Spring容器中,是通过RootBeanDefinition表示的 如下图:
在这里插入图片描述
因为bean标签中没有设置parent属性的值,也就是说它没有指定自己的父bean,所以可以使用RootBeanDefinition 来封装这个标签的信息。

我们还可以看RootBeanDefinition的setParentName方法中,如果参数parentName不为空还会报错:
在这里插入图片描述
这样就很明显了,通过RootBeanDefinition来封装bean的信息时,就不允许在有父类了。

但是,如果 bean的标签中设置parent属性,如下图:
在这里插入图片描述
可以看到,id属性值为teacher的bean标签,将parent属性值设置为user,也就是说它把id属性值为user的bean标签作为自己的父标签,这个时候Spring就会将id 为teacher的bean标签信息,封装在childBeanDefinition这个类中了。

所以RootBeanDefinition和ChildBeanDefinition 在早期的Spring版本中,大概就是这样使用的,但是随着Spring后续版本的迭代,Spring更加推荐我们使用GenericBeanDefinition:
在这里插入图片描述
可以看到,从Spring2.5 版本开始,Spring就推荐我能使用GenericBeanDefinition 来代替RootBeanDefinition 和ChildBeanDefinition,如果是子标签,GenericBeanDefinition 可以通过setParentName 方法 来设置parent属性值。
GenericBeanDefinition 中包含了RootBeanDefinition 和ChilBeanDefinition的所有的公共属性和方法,是一个更通用的BeanDefinition,在上一篇中,Spring 解析bean标签中创建的BeanDefinition就是GenericBeanDefinition 类型了。

在上面的BeanDefinition的类图中,我们还看到AnnotatedGenericBeanDefinition 这个类。从名称上面我们也可以看出来,这个就是用来封装和注解相关的bean。也就是说,AnnotatedBeanDefinition专门是用来封装从注解扫描解析来的bean,比如@Service @Repository @Bean 等等,我们到后面分析注解源码的时候会具体讲的。

那么BeanDefinition 中有哪些东西呢?

我们下面来看下这个BeanDefinition中包含哪些东西:
在这里插入图片描述
在BeanDefinition中,都是Bean的一些属性的相关方法。
我们知道,xml中所有配置都是封装在GenericBeanDefinition中,而GenericBeanDefinition 只是一个实现类,一些通用的属性其实都是保存在AbstractBeanDefinition中的。
在这里插入图片描述
可以看到,在AbstractBeanDefinition中,封装了很多公共的属性。
Spring容器中的每个bean中的信息都封装在BeanDefinition中,其中AbstractBeanDefinition 实现了BeanDefinition接口的抽象类,包含了xml以及注册bean类型的公共方法和属性。

在了解了BeanDefinition之后,我们接着上一篇中源码进行分析:
在这里插入图片描述
上一篇中,我们通过createBeanDefinition方法创建了GenericBeanDefinition对象。
接下来,我们接着看这个parseBeanDefinitionAttributes 方法在干什么,从这个方法名称我们大概知道这个是要解析bean中所有的属性了。

/**
	 * Apply the attributes of the given bean element to the given bean * definition.
	 * @param ele bean declaration element
	 * @param beanName bean name
	 * @param containingBean containing bean definition
	 * @return a bean definition initialized according to the bean element attributes
	 */
	public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName,
			@Nullable BeanDefinition containingBean, AbstractBeanDefinition bd) {
		
		// 如果bean 标签中存在singleton 属性,就提示错误信息,表示singleton 需要通过scope声明
		if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {
			error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele);
		}
		
		// 如果bean标签中 存在scope 属性 ,就获取这个scope属性值,然后设置到bd对象中
		else if (ele.hasAttribute(SCOPE_ATTRIBUTE)) {
			bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE));
		}
		else if (containingBean != null) {
			// Take default from containing bean in case of an inner bean definition.
			bd.setScope(containingBean.getScope());
		}

		// 获取属性Abstract的值
		if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) {
			bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE)));
		}
		
		// 获取属性lazy-init的值
		String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE);
		if (isDefaultValue(lazyInit)) {
			lazyInit = this.defaults.getLazyInit();
		}
		bd.setLazyInit(TRUE_VALUE.equals(lazyInit));
		
		//获取属性autowire的值
		String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE);
		bd.setAutowireMode(getAutowireMode(autowire));

		// 获取属性depends-on的值
		if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) {
			String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE);
			bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, MULTI_VALUE_ATTRIBUTE_DELIMITERS));
		}

		// 获取属性autowire-candidate的值
		String autowireCandidate = ele.getAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE);
		if (isDefaultValue(autowireCandidate)) {
			String candidatePattern = this.defaults.getAutowireCandidates();
			if (candidatePattern != null) {
				String[] patterns = StringUtils.commaDelimitedListToStringArray(candidatePattern);
				bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName));
			}
		}
		else {
			bd.setAutowireCandidate(TRUE_VALUE.equals(autowireCandidate));
		}

		// 获取属性primary的值
		if (ele.hasAttribute(PRIMARY_ATTRIBUTE)) {
			bd.setPrimary(TRUE_VALUE.equals(ele.getAttribute(PRIMARY_ATTRIBUTE)));
		}

		// 获取属性init-method的值
		if (ele.hasAttribute(INIT_METHOD_ATTRIBUTE)) {
			String initMethodName = ele.getAttribute(INIT_METHOD_ATTRIBUTE);
			bd.setInitMethodName(initMethodName);
		}
		else if (this.defaults.getInitMethod() != null) {
			bd.setInitMethodName(this.defaults.getInitMethod());
			bd.setEnforceInitMethod(false);
		}

		// 获取属性destroy-method的值
		if (ele.hasAttribute(DESTROY_METHOD_ATTRIBUTE)) {
			String destroyMethodName = ele.getAttribute(DESTROY_METHOD_ATTRIBUTE);
			bd.setDestroyMethodName(destroyMethodName);
		}
		else if (this.defaults.getDestroyMethod() != null) {
			bd.setDestroyMethodName(this.defaults.getDestroyMethod());
			bd.setEnforceDestroyMethod(false);
		}
		
		// 获取factory-method的值
		if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) {
			bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE));
		}
		if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) {
			bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE));
		}

		return bd;
	}

可以看到,方法parseBeanDefinitionAttributes中解析各种各样的属性,解析的这些属性和id、name、class 和parent一样都会封装在GenericBeanDefinition中。
当bean标签的各种属性解析完了之后,接着就会开始解析bean 标签下的各种子标签了:
在这里插入图片描述
在这些子标签中,包括meta、lookup-method、replaced-method、constructor-args、property和qualifier,其中我们比较常用的还是标签property 和 constructor-args 。 下一篇我们看下Spring是如何解析这些字标签元素的。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

youngerone123

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值