Spring5IOC容器解析——BeanDefinition的注
前言
在上一篇文章解析BeanDefinition
对配置文件解析完成后,获取的beanDefiniton已经可以进行使用了,剩下的唯一工作就是注册了,也就是processBeanDefinition方法中的BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry())代码的解析了。
BeanDefinitionRegistry
该类的作用主要是向注册表中注册 BeanDefinition 实例,完成 注册的过程。
它的接口定义如下:
public interface BeanDefinitionRegistry extends AliasRegistry {
/**
* 往注册表中注册一个新的 BeanDefinition 实例
* Register a new bean definition with this registry.
* Must support RootBeanDefinition and ChildBeanDefinition.
* @param beanName the name of the bean instance to register
* @param beanDefinition definition of the bean instance to register
* @throws BeanDefinitionStoreException if the BeanDefinition is invalid
* @throws BeanDefinitionOverrideException if there is already a BeanDefinition
* for the specified bean name and we are not allowed to override it
* @see GenericBeanDefinition
* @see RootBeanDefinition
* @see ChildBeanDefinition
*/
void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException;
/**
* 移除注册表中已注册的 BeanDefinition 实例
* Remove the BeanDefinition for the given name.
* @param beanName the name of the bean instance to register
* @throws NoSuchBeanDefinitionException if there is no such bean definition
*/
void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
/**
* 从注册中取得指定的 BeanDefinition 实例
* Return the BeanDefinition for the given bean name.
* @param beanName name of the bean to find a definition for
* @return the BeanDefinition for the given name (never {@code null})
* @throws NoSuchBeanDefinitionException if there is no such bean definition
*/
BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
/**
* 判断 BeanDefinition 实例是否在注册表中(是否注册)
* Check if this registry contains a bean definition with the given name.
* @param beanName the name of the bean to look for
* @return if this registry contains a bean definition with the given name
*/
boolean containsBeanDefinition(String beanName);
/**
* 取得注册表中所有 BeanDefinition 实例的 beanName(标识)
* Return the names of all beans defined in this registry.
* @return the names of all beans defined in this registry,
* or an empty array if none defined
*/
String[] getBeanDefinitionNames();
/**
* 返回注册表中 BeanDefinition 实例的数量
* Return the number of beans defined in the registry.
* @return the number of beans defined in the registry
*/
int getBeanDefinitionCount();
/**
* beanName(标识)是否被占用
* Determine whether the given bean name is already in use within this registry,
* i.e. whether there is a local bean or alias registered under this name.
* @param beanName the name to check
* @return whether the given bean name is already in use
*/
boolean isBeanNameInUse(String beanName);
}
再来看BeanDefinitionRegistry的继承关系,DefaultListableBeanFactory赫然在列:
DefaultListableBeanFactory
该类是 BeanDefinitionRegistry 接口的基本实现类,但同时也实现其他了接口的功能,这里只探究下其关于注册 BeanDefinition 实例的相关方法 。
首先来看它的成员变量:
// 关键-> 注册表,由 BeanDefinition 的标识 (beanName) 与其实例组成
/** Map of bean definition objects, keyed by bean name. */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
// 标识(beanName)集合
/** List of bean definition names, in registration order. */
private volatile List<String> beanDefinitionNames = new ArrayList<>(256);
现在进入DefaultBeanDefinitionDocumentReader类的processBeanDefinition方法
/**
* Process the given bean element, parsing the bean definition
* and registering it with the registry.
* 解析BeanDefinition资源
*/
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// BeanDefinitionHolder是对BeanDefinition的封装,即Bean定义的封装类
//对Document对象中<Bean>元素的解析由BeanDefinitionParserDelegate实现
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// Register the final decorated instance.
//向Spring IOC容器注册解析得到的BeanDefinition,这是BeanDefinition向IOC容器注册的入口
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// Send registration event.
// 在完成BeanDefinition注册之后,往容器发送注册完成的事件
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
再来看 BeanDefinitionReaderUtils 的 registerBeanDefinition 方法。该方法的主要作用是调用注册器(DefaultListableBeanFactory)完成注册过程。
/**
* 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类型的实例中,而对于beanDefinition的注册分成了两部分:通过beanName的注册以及通过别名的注册。
1、通过beanName注册BeanDefinition
对于beanDefinition的注册,是将beanDefinition直接放入了map中,以beanName为key。但不仅仅如此,代码如下:
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
/** Resolver to use for checking if a bean definition is an autowire candidate. */
private AutowireCandidateResolver autowireCandidateResolver = new SimpleAutowireCandidateResolver();
/** Map from dependency type to corresponding autowired value. */
private final Map<Class<?>, Object> resolvableDependencies = new ConcurrentHashMap<>(16);
// 关键-> 注册表,由 BeanDefinition 的标识 (beanName) 与其实例组成
/** Map of bean definition objects, keyed by bean name. */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
/** Map from bean name to merged BeanDefinitionHolder. */
private final Map<String, BeanDefinitionHolder> mergedBeanDefinitionHolders = new ConcurrentHashMap<>(256);
/** Map of singleton and non-singleton bean names, keyed by dependency type. */
private final Map<Class<?>, String[]> allBeanNamesByType = new ConcurrentHashMap<>(64);
/** Map of singleton-only bean names, keyed by dependency type. */
private final Map<Class<?>, String[]> singletonBeanNamesByType = new ConcurrentHashMap<>(64);
// 标识(beanName)集合
/** List of bean definition names, in registration order. */
private volatile List<String> beanDefinitionNames = new ArrayList<>(256);
/** List of names of manually registered singletons, in registration order. */
private volatile Set<String> manualSingletonNames = new LinkedHashSet<>(16);
/** Cached array of bean definition names in case of frozen configuration. */
@Nullable
private volatile String[] frozenBeanDefinitionNames;
/** Whether bean definition metadata may be cached for all beans. */
private volatile boolean configurationFrozen = false;
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
// 校验 beanName 与 beanDefinition 非空
Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
/**
* 1、校验 BeanDefinition
* 注册前的最后一次校验,这里的校验不同于之前的XML文件校验,
* 主要是对于AbstractBeanDefinition属性中的lookup-method属性和replaced-method属性对应的重写方法是否存在并且合法,
* 校验methodOverrides是否与工厂方法并存或者methodOverrides对应的方法根本不存在
*/
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
// 2、从缓存中获取指定 beanName 的 BeanDefinition
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
//3、看看beanName是否已经存在容器里,存在则表明已经被注册过
if (existingDefinition != null) {
// 如果存在但是不允许覆盖,抛出异常
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
}
// 覆盖 beanDefinition 大于 被覆盖的 beanDefinition 的 ROLE ,打印 info 日志
else if (existingDefinition.getRole() < beanDefinition.getRole()) {
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
if (logger.isInfoEnabled()) {
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
logger.info("Overriding user-defined bean definition for bean '" + beanName +
"' with a framework-generated bean definition: replacing [" +
existingDefinition + "] with [" + beanDefinition + "]");
}
}
// 覆盖 beanDefinition 与 被覆盖的 beanDefinition 不相同,打印 debug 日志
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 {
// 其它,打印 debug 日志
if (logger.isTraceEnabled()) {
logger.trace("Overriding bean definition for bean '" + beanName +
"' with an equivalent definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
// 允许覆盖,直接覆盖原有的 BeanDefinition 到 beanDefinit 大专栏 注册BeanDefinitions-下ionMap 中。
this.beanDefinitionMap.put(beanName, beanDefinition);
}
//4、如果未存在
else {
// 检测创建 Bean 阶段是否已经开启,如果开启了则需要对 beanDefinitionMap 进行并发控制
if (hasBeanCreationStarted()) {
// beanDefinitionMap 为全局变量,避免并发情况
// Cannot modify startup-time collection elements anymore (for stable iteration)
synchronized (this.beanDefinitionMap) {
// 添加BeanDefinition 到 beanDefinitionMap 中。
this.beanDefinitionMap.put(beanName, beanDefinition);
// 添加 beanName 到 beanDefinitionNames 中
List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
// 从 manualSingletonNames 移除 beanName
removeManualSingletonName(beanName);
}
}
else {
// Still in startup registration phase
// 添加 BeanDefinition 到 beanDefinitionMap 中。
this.beanDefinitionMap.put(beanName, beanDefinition);
// 添加 beanName 到 beanDefinitionNames 中
this.beanDefinitionNames.add(beanName);
// 从 manualSingletonNames 移除 beanName
removeManualSingletonName(beanName);
}
//将注册期间被冻结的BeanDefinition的名字列表清除掉
this.frozenBeanDefinitionNames = null;
}
// 5、重新设置 beanName 对应的缓存
//检查是否有同名的BeanDefinition已经在IOC容器中注册
if (existingDefinition != null || containsSingleton(beanName)) {
//尝试重置所有已经注册过的BeanDefinition的缓存,包括BeanDefinition
//的父类以及合并的beanDefinition的缓存,所谓的合并BeanDefinition
//指的的有parent属性的beandefinition,该BeanDefinition会把parent的
//BeanDefinition属性合并在一块
resetBeanDefinition(beanName);
}
else if (isConfigurationFrozen()) {
clearByTypeCache();
}
}
}
上面的代码中我们看到,在对于bean的注册处理方式上,主要进行了几个步骤:
- 1、对AbstractBeanDefinition的校验。在解析XML文件的时候我们提过校验,但是此校验非彼校验,之前的校验是针对XML格式的校验,而此时的校验是针对AbstractBeanDefinition的methodOverrides属性的。
- 2、对beanName已经注册的情况的处理。如果设置了不允许bean的覆盖,则需要抛出异常,否则直接覆盖。
- 3、加入map缓存。
- 4、清楚解析之前留下的对应beanName的缓存。
2、通过别名注册BeanDefinition
在理解了注册bean的原理后,理解注册别名的原理就容易多了。
先看别名注册接口AliasRegistry
public interface AliasRegistry {
/**
* 注册表中给name注册一个别名alias
* Given a name, register an alias for it.
* @param name the canonical name
* @param alias the alias to be registered
* @throws IllegalStateException if the alias is already in use
* and may not be overridden
*/
void registerAlias(String name, String alias);
/**
* 移除注册表中的别名alias
* Remove the specified alias from this registry.
* @param alias the alias to remove
* @throws IllegalStateException if no such alias was found
*/
void removeAlias(String alias);
/**
* 校验注册表中是否存在别名name
* Determine whether the given name is defined as an alias
* (as opposed to the name of an actually registered component).
* @param name the name to check
* @return whether the given name is an alias
*/
boolean isAlias(String name);
/**
* 在注册表中获取给定那么的所有别名信息
* Return the aliases for the given name, if defined.
* @param name the name to check for aliases
* @return the aliases, or an empty array if none
*/
String[] getAliases(String name);
}
接着跟进registry.registerAlias(beanName, alias)
public class SimpleAliasRegistry implements AliasRegistry {
//别名-规范名称的映射MAP,用于存储注册信息(内存注册表)
/** Map from alias to canonical name. */
private final Map<String, String> aliasMap = new ConcurrentHashMap<>(16);
//注册表中注册别名
@Override
public void registerAlias(String name, String alias) {
Assert.hasText(name, "'name' must not be empty");
Assert.hasText(alias, "'alias' must not be empty");
//锁注册表
//因为CurrentHashMap只有put和remove是线程安全的
//此处要包装对CurrentHashMap的复合操作线程安全
synchronized (this.aliasMap) {
// 如果beanName与alias相同的话不记录alias,并删除对应的alias
if (alias.equals(name)) {
//如果别名与名字相同,则在Map中移除
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;
}
//判断是否允许重写注册
if (!allowAliasOverriding()) {
throw new IllegalStateException("Cannot define alias '" + alias + "' for name '" +
name + "': It is already registered for name '" + registeredName + "'.");
}
if (logger.isDebugEnabled()) {
logger.debug("Overriding alias '" + alias + "' definition for registered name '" +
registeredName + "' with new target name '" + name + "'");
}
}
// // 校验规范名称是否指向当前别名的
checkForAliasCircle(name, alias);
// 注册表注册别名与规范名称的映射
this.aliasMap.put(alias, name);
if (logger.isTraceEnabled()) {
logger.trace("Alias definition '" + alias + "' registered for name '" + name + "'");
}
}
}
}
}
由以上代码中可以得知注册alias的步骤如下:
- 1、beanName与alias相同情况处理。若alias和beanName名称相同则不需要处理并删除原有的alias。
- 2、alias覆盖处理。若aliasName已经使用并已经指向了另一beanName则需要用户的设置进行处理。
- 3、alias循环检查。当A -> B存在时,若再次出现 A -> C -> B时候则会抛出异常。
- 4、注册alias。
SimpleAliasRegistry的其他方法
public class SimpleAliasRegistry implements AliasRegistry {
/** Logger available to subclasses. */
protected final Log logger = LogFactory.getLog(getClass());
//别名-规范名称的映射MAP,用于存储注册信息(内存注册表)
/** Map from alias to canonical name. */
private final Map<String, String> aliasMap = new ConcurrentHashMap<>(16);
//注册表中注册别名
@Override
public void registerAlias(String name, String alias) {
Assert.hasText(name, "'name' must not be empty");
Assert.hasText(alias, "'alias' must not be empty");
//锁注册表
//因为CurrentHashMap只有put和remove是线程安全的
//此处要包装对CurrentHashMap的复合操作线程安全
synchronized (this.aliasMap) {
// 如果beanName与alias相同的话不记录alias,并删除对应的alias
if (alias.equals(name)) {
//如果别名与名字相同,则在Map中移除
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;
}
//判断是否允许重写注册
if (!allowAliasOverriding()) {
throw new IllegalStateException("Cannot define alias '" + alias + "' for name '" +
name + "': It is already registered for name '" + registeredName + "'.");
}
if (logger.isDebugEnabled()) {
logger.debug("Overriding alias '" + alias + "' definition for registered name '" +
registeredName + "' with new target name '" + name + "'");
}
}
// // 校验规范名称是否指向当前别名的
checkForAliasCircle(name, alias);
// 注册表注册别名与规范名称的映射
this.aliasMap.put(alias, name);
if (logger.isTraceEnabled()) {
logger.trace("Alias definition '" + alias + "' registered for name '" + name + "'");
}
}
}
}
/**
* 是否允许重写注册表别名信息,默认true
* Determine whether alias overriding is allowed.
* <p>Default is {@code true}.
*/
protected boolean allowAliasOverriding() {
return true;
}
/**
* 校验给定的name-alias映射是否已在注册表aliasMap中
* Determine whether the given name has the given alias registered.
* @param name the name to check
* @param alias the alias to look for
* @since 4.2.1
*/
public boolean hasAlias(String name, String alias) {
//获取注册表中单映射的规范名称name
String registeredName = this.aliasMap.get(alias);
return ObjectUtils.nullSafeEquals(registeredName, name) || (registeredName != null
&& hasAlias(name, registeredName));
}
/**
* 移除别名,在注册表aliasMap中
* @param alias the alias to remove
*/
@Override
public void removeAlias(String alias) {
synchronized (this.aliasMap) {
String name = this.aliasMap.remove(alias);
if (name == null) {
throw new IllegalStateException("No alias '" + alias + "' registered");
}
}
}
//校验是否包含给定的别名,在注册表中
@Override
public boolean isAlias(String name) {
return this.aliasMap.containsKey(name);
}
// 在注册表获取给定规范名称的所有别名信息
@Override
public String[] getAliases(String name) {
List<String> result = new ArrayList<>();
synchronized (this.aliasMap) {
retrieveAliases(name, result);
}
return StringUtils.toStringArray(result);
}
/**
* Transitively retrieve all aliases for the given name.
* @param name the target name to find aliases for
* @param result the resulting aliases list
*/
private void retrieveAliases(String name, List<String> result) {
this.aliasMap.forEach((alias, registeredName) -> {
//判断当前别名的规范名称是否为要查询的
if (registeredName.equals(name)) {
result.add(alias);
//递归查询循环引用的别名
retrieveAliases(alias, result);
}
});
}
/**
* Resolve all alias target names and aliases registered in this
* registry, applying the given {@link StringValueResolver} to them.
* <p>The value resolver may for example resolve placeholders
* in target bean names and even in alias names.
* @param valueResolver the StringValueResolver to apply
*/
public void resolveAliases(StringValueResolver valueResolver) {
Assert.notNull(valueResolver, "StringValueResolver must not be null");
synchronized (this.aliasMap) {
Map<String, String> aliasCopy = new HashMap<>(this.aliasMap);
aliasCopy.forEach((alias, registeredName) -> {
String resolvedAlias = valueResolver.resolveStringValue(alias);
String resolvedName = valueResolver.resolveStringValue(registeredName);
if (resolvedAlias == null || resolvedName == null || resolvedAlias.equals(resolvedName)) {
this.aliasMap.remove(alias);
}
else if (!resolvedAlias.equals(alias)) {
String existingName = this.aliasMap.get(resolvedAlias);
if (existingName != null) {
if (existingName.equals(resolvedName)) {
// Pointing to existing alias - just remove placeholder
this.aliasMap.remove(alias);
return;
}
throw new IllegalStateException(
"Cannot register resolved alias '" + resolvedAlias + "' (original: '" + alias +
"') for name '" + resolvedName + "': It is already registered for name '" +
registeredName + "'.");
}
checkForAliasCircle(resolvedName, resolvedAlias);
this.aliasMap.remove(alias);
this.aliasMap.put(resolvedAlias, resolvedName);
}
else if (!registeredName.equals(resolvedName)) {
this.aliasMap.put(alias, resolvedName);
}
});
}
}
/**
* 校验给定的名称是否指向别名,不指向异常抛出
* Check whether the given name points back to the given alias as an alias
* in the other direction already, catching a circular reference upfront
* and throwing a corresponding IllegalStateException.
* @param name the candidate name
* @param alias the candidate alias
* @see #registerAlias
* @see #hasAlias
*/
protected void checkForAliasCircle(String name, String alias) {
if (hasAlias(alias, name)) {
throw new IllegalStateException("Cannot register alias '" + alias +
"' for name '" + name + "': Circular reference - '" +
name + "' is a direct or indirect alias for '" + alias + "' already");
}
}
/**
* 根据给定的别名获取规范名称
* Determine the raw name, resolving aliases to canonical names.
* @param name the user-specified name
* @return the transformed name
*/
public String canonicalName(String name) {
String canonicalName = name;
// Handle aliasing...
String resolvedName;
do {
//获取给定别名的规范名称,获取到跳出循环
resolvedName = this.aliasMap.get(canonicalName);
if (resolvedName != null) {
canonicalName = resolvedName;
}
}
while (resolvedName != null);
return canonicalName;
}
}
SimpleBeanDefinitionRegistry 为BeanDefinitionRegistry的默认实现,同时继承AliasRegistry的默认实现SimpleAliasRegistry,所以它总共维护了两个注册表aliasMap(别名注册表)与beanDefinitionMap(bean描述注册表),到此AliasRegistry接口功能的主要实现以及扩展接口的主要实现通过源码已清晰展示
参考:
https://www.cnblogs.com/monkey0307/p/8509701.html
https://www.cnblogs.com/warehouse/p/9380473.html
https://www.cnblogs.com/moxiaotao/p/9349549.html