spring源码学习之默认标签的解析(二)

  这个是接着上一篇来写,主要是这章内容比较多,还是分开来写吧!

一、AbstractBeanDefinition属性介绍

XML中的所有的属性都可以在GenericBeanDefinition中找到对应,GenericBeanDefinition只是子类实现,大部分通用的配置都在
其父类AbstractBeanDefinition中定义,来看一下AbstractBeanDefinition中有哪些属性定义,因为我看的是spring5.0版本,和作者的版本应该不一样,这里是少了两个属性的就是scope和singleton,我下面是spring5.0的源码:

 /**
* bean的作用范围,对应bean的属性scope
*/
@Nullable
private String scope = SCOPE_DEFAULT; /**
* 是否是抽象,对应bean属性abstract
*/
private boolean abstractFlag = false; /**
* 是否延迟加载,对应bean属性lazy-init
*/
private boolean lazyInit = false; /**
* 自动注入模式,对应bean属性autowire
*/
private int autowireMode = AUTOWIRE_NO; /**
* 依赖检查,spring3.0之后弃用这个属性
*/
private int dependencyCheck = DEPENDENCY_CHECK_NONE; /**
* 用来表示一个bean的实例化依靠另一个bean先实例化,对应bean的属性depend-on
*/
@Nullable
private String[] dependsOn; /**
* autowireCandidate属性设置成flase时,这样容器在查找自动装配对象时,将不考虑该bean,<br>
* 即它不会被考虑作为其他bean的自动装配的候选者,但是该bean本身还是可以使用自动装配来注入其他bean的
*/
private boolean autowireCandidate = true; /**
* 自动装配时当出现多个bean候选者的时候,将作为首先,对应bean属性primary
*/
private boolean primary = false; /**
* 用于记录Qualifier,对应子元素qualifier
*/
private final Map<String, AutowireCandidateQualifier> qualifiers = new LinkedHashMap<>(); /**
* 这个好像是新加的属性 TODO
*/
@Nullable
private Supplier<?> instanceSupplier; /**
* 允许访问非公开的构造器和方法,程序设置
*/
private boolean nonPublicAccessAllowed = true; /**
* 是否以一种宽松的方式解析构造函数,默认为true <br>
*/
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; /**
* 定义这个bean的应用
* APPLICATION:用户
* INFRASTRUCTURE:完全内部使用,与用户无关
* SUPPORT:某些复杂配置的一部分
* 程序设置
*/
private int role = BeanDefinition.ROLE_APPLICATION; /**
* bean的描述信息
*/
@Nullable
private String description; /**
* bean定义的资源
*/
@Nullable
private Resource resource;

二、注册解析BeanDefinition

org.springframework.beans.factory.xml包下的DefaultBeanDefinitionDocumentReader类中processBeanDefinition方法中的
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());这行代码进行注册操作
BeanDefinitionReaderUtils所在的包:org.springframework.beans.factory.support,看一下registerBeanDefinition方法的源码

 /**
* Register the given bean definition with the given bean factory.
* @param definitionHolder the bean definition including name and aliases
* @param registry the bean factory to register with
* @throws BeanDefinitionStoreException if registration failed
*/
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException { // Register bean definition under primary name.
// 使用beanName作为唯一标识
String beanName = definitionHolder.getBeanName();
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); // Register aliases for bean name, if any.
// 注册所有的别名
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}

通过上面的代码,可以看出,解析的BeanDefinition都会被注册到BeanDefinitionRegistry类型的registry实例中,而对于
BeanDefinition的注册分成了两部分,通过beanName的注册以及通过别名的注册

1、通过beanName的注册BeanDefinition
对于BeanDefinition的注册,或许我们都认为是将BeanDefinition直接放入map中,使用beanName作为key,确实spring是这么做的,
只不过,除此之外,还做了点别的事情
注意:这里spring中的BeanDefinitionRegistry是以接口形式存在的,它有三个实现类,分别是GenericApplicationContext、DefaultListableBeanFactory和
SimpleBeanDefinitionRegistry,其中SimpleBeanDefinitionRegistry类中的方法实现是没做任何事情,只是将其放入map中,其他两个实现类的处理逻辑是一样的
,只不过在GenericApplicationContext中创建了一个DefaultListableBeanFactory实例,来调用DefaultListableBeanFactory中的注册方法,所有,来看下
DefaultListableBeanFactory中registerBeanDefinition方法

org.springframework.beans.factory.support包下的DefaultListableBeanFactory类中:

 @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 {
/**
* 注册前的最后一次验证,这里的校验不同于之前的XML文件校验<br>
* 主要是对于AbstractBeanDefinition属性中的methodOverrides校验<br>
* 验证methodOverrides是否与工厂方法共存或者methodOverrides对应的方法根本不存在
*/
((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 BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
"': There is already [" + existingDefinition + "] bound.");
}
else if (existingDefinition.getRole() < beanDefinition.getRole()) {
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
if (logger.isWarnEnabled()) {
logger.warn("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.isInfoEnabled()) {
logger.info("Overriding bean definition for bean '" + beanName +
"' with a different definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Overriding bean definition for bean '" + beanName +
"' with an equivalent definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
// 已经创建至少一次的bean的名称
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
// 因为beanDefinitionMap是全局变量,这里肯定存在并发访问的问题
synchronized (this.beanDefinitionMap) {
// 处理beanName的存储问题
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;
}
}
}
// bean没有被创建过
else {
// Still in startup registration phase
// 注册beanDefinition并记录beanName
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
this.manualSingletonNames.remove(beanName);
}
this.frozenBeanDefinitionNames = null;
} if (existingDefinition != null || containsSingleton(beanName)) {
// 重置所有beanName对应的缓存
resetBeanDefinition(beanName);
}
}

注意:这里跟作者书中的代码有些出入,不知道难道是我下载的版本和作者不一样,不知道,反正总体的处理逻辑是一样的,只是这段代码是
处理的情况更加完善一些!

2、通过别名注册BeanDefinition

同样这个是在AliasRegistry接口中,BeanDefinitionRegistry是AliasRegistry的实现类,找到AliasRegistry类中registerAlias方法,进而找到实现类中方法实现
最终在org.springframework.core包下的SimpleAliasRegistry类中,源码如下:

 @Override
public void registerAlias(String name, String alias) {
Assert.hasText(name, "'name' must not be empty");
Assert.hasText(alias, "'alias' must not be empty");
// aliasMap是全局变量,肯定存在并发问题
synchronized (this.aliasMap) {
// 如果alias与beanName相同的话,不记录alias
if (alias.equals(name)) {
this.aliasMap.remove(alias);
if (logger.isDebugEnabled()) {
logger.debug("Alias definition '" + alias + "' ignored since it points to same name");
}
}
else {
String registeredName = this.aliasMap.get(alias);
if (registeredName != null) {
if (registeredName.equals(name)) {
// An existing alias - no need to re-register
return;
}
// 如果alias别名不允许被覆盖则抛出异常
if (!allowAliasOverriding()) {
throw new IllegalStateException("Cannot define alias '" + alias + "' for name '" +
name + "': It is already registered for name '" + registeredName + "'.");
}
if (logger.isInfoEnabled()) {
logger.info("Overriding alias '" + alias + "' definition for registered name '" +
registeredName + "' with new target name '" + name + "'");
}
}
// 当A->B,存在时,若再次出现A->C->B则抛出异常
checkForAliasCircle(name, alias);
// 注册别名
this.aliasMap.put(alias, name);
if (logger.isDebugEnabled()) {
logger.debug("Alias definition '" + alias + "' registered for name '" + name + "'");
}
}
}
}

三、通知监听器解析及注册完成

通过代码getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
完成此工作,这里的实现只为扩展,当程序开发人员需要对注册BeanDefinition事件进行监听时可以通过注册监听器的方式
并将处理逻辑写在监听器中,目前spring中没有对此进行处理

四、alias标签的解析

alias标签,就是给bean起个别名,反正我是没用过这个,大概写一下吧!
用法如下:
1)<bean id="testBean" name="testBean2,testBean" class="com.test"></bean>
2)<bean id="testBean" class="com.test"></bean>
<alias name="testBean" alias="testBean2,testBean" />

源码解读:
org.springframework.beans.factory.xml包下DefaultBeanDefinitionDocumentReader类中的processAliasRegistration方法

 /**
* Process the given alias element, registering the alias with the registry.
*/
protected void processAliasRegistration(Element ele) {
// 获取beanName
String name = ele.getAttribute(NAME_ATTRIBUTE);
// 获取alias
String alias = ele.getAttribute(ALIAS_ATTRIBUTE);
boolean valid = true;
if (!StringUtils.hasText(name)) {
getReaderContext().error("Name must not be empty", ele);
valid = false;
}
if (!StringUtils.hasText(alias)) {
getReaderContext().error("Alias must not be empty", ele);
valid = false;
}
if (valid) {
try {
// 注册alias
getReaderContext().getRegistry().registerAlias(name, alias);
}
catch (Exception ex) {
getReaderContext().error("Failed to register alias '" + alias +
"' for bean with name '" + name + "'", ele, ex);
}
// 注册别名后通知监听器做相应处理
getReaderContext().fireAliasRegistered(name, alias, extractSource(ele));
}
}

五、import标签的解析

import标签实现了模块的划分,可以使得配置文件模块化,主要归结于import标签的功劳,
主要就是引入其他的
<import resource="customerContext.xml" />
<import resource="systemContext.xml" />

源码解读:
org.springframework.beans.factory.xml包下DefaultBeanDefinitionDocumentReader类中的importBeanDefinitionResource方法

 /**
* Parse an "import" element and load the bean definitions
* from the given resource into the bean factory.
*/
protected void importBeanDefinitionResource(Element ele) {
// 获取resource属性
String location = ele.getAttribute(RESOURCE_ATTRIBUTE);
// 如果不存在resource属性则不做任何处理
if (!StringUtils.hasText(location)) {
getReaderContext().error("Resource location must not be empty", ele);
return;
} // Resolve system properties: e.g. "${user.dir}"
// 解析系统属性 格式如:"${user.dir}"
location = getReaderContext().getEnvironment().resolveRequiredPlaceholders(location); Set<Resource> actualResources = new LinkedHashSet<>(4); // Discover whether the location is an absolute or relative URI
// 判断location是绝对路径还是相对路径
boolean absoluteLocation = false;
try {
absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute();
}
catch (URISyntaxException ex) {
// cannot convert to an URI, considering the location relative
// unless it is the well-known Spring prefix "classpath*:"
} // Absolute or relative?
// 如果是绝对路径URI 则直接根据地址加载对应的配置文件
if (absoluteLocation) {
try {
int importCount = getReaderContext().getReader().loadBeanDefinitions(location, actualResources);
if (logger.isDebugEnabled()) {
logger.debug("Imported " + importCount + " bean definitions from URL location [" + location + "]");
}
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error(
"Failed to import bean definitions from URL location [" + location + "]", ele, ex);
}
}
else {
// No URL -> considering resource location as relative to the current file.
// 如果是相对路径,则根据相对路径计算出绝对路径
try {
int importCount;
/**
* Resource存在多个实现类,如直接选中之后,快捷键Ctrl+T查看其实现类<br>
* 而每个Resource的createRelative实现都不一样,所以这里先尝试子类的方法进行尝试解析
*/
Resource relativeResource = getReaderContext().getResource().createRelative(location);
if (relativeResource.exists()) {
importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource);
actualResources.add(relativeResource);
}
// 如果解析不成功,则使用默认的解析器ResourcePatternResolver进行解析,这个有点太复杂了,好多实现类,理不清楚!
else {
String baseLocation = getReaderContext().getResource().getURL().toString();
importCount = getReaderContext().getReader().loadBeanDefinitions(
StringUtils.applyRelativePath(baseLocation, location), actualResources);
}
if (logger.isDebugEnabled()) {
logger.debug("Imported " + importCount + " bean definitions from relative location [" + location + "]");
}
}
catch (IOException ex) {
getReaderContext().error("Failed to resolve current resource location", ele, ex);
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to import bean definitions from relative location [" + location + "]",
ele, ex);
}
}
// 解析后进行监听器激活处理
Resource[] actResArray = actualResources.toArray(new Resource[0]);
getReaderContext().fireImportProcessed(location, actResArray, extractSource(ele));
}
上一篇:Spring-cloud微服务 Eureka学习教程-单服务器配置之快速搭建EurekaServer、EurekaClient(基础)


下一篇:soapUI学习笔记--用例字段参数化