www.91084.com

GVKun编程网logo

Spring 源码第六弹!松哥和大家聊聊容器的始祖 DefaultListableBeanFactory(spring容器原理)

22

对于想了解Spring源码第六弹!松哥和大家聊聊容器的始祖DefaultListableBeanFactory的读者,本文将是一篇不可错过的文章,我们将详细介绍spring容器原理,并且为您提供关于D

对于想了解Spring 源码第六弹!松哥和大家聊聊容器的始祖 DefaultListableBeanFactory的读者,本文将是一篇不可错过的文章,我们将详细介绍spring容器原理,并且为您提供关于DefaultListableBeanFactory、DefaultListableBeanFactory 架构图、DefaultListableBeanFactory 源码 分析、DefaultListBeanFactory的子类之SimpleAliasRegistry的有价值信息。

本文目录一览:

Spring 源码第六弹!松哥和大家聊聊容器的始祖 DefaultListableBeanFactory(spring容器原理)

Spring 源码第六弹!松哥和大家聊聊容器的始祖 DefaultListableBeanFactory(spring容器原理)

松哥原创的 Spring Boot 视频教程已经杀青,感兴趣的小伙伴戳这里-->Spring Boot+Vue+微人事视频教程

Spring 源码继续开整!

在 XML 文件解析流程一文中,松哥和大家分享了 Spring 中配置文件的加载方式,如果小伙伴们还没看过,一定先看一下,这有助于更好的理解本文,传送门:Spring 源码第一篇开整!配置文件是怎么加载的?。

还记得该篇文章中的代码吗?

XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource("beans.xml"));
User user = factory.getBean(User.class);
System.out.println("user = " + user);

当 ClassPathResource 将文件以 IO 流的方式输出后,接下来就是构造 XmlBeanFactory ,XmlBeanFactory 功能有限,它的大部分功能都在它的父类 DefaultListableBeanFactory 中实现了,而 DefaultListableBeanFactory 也相当于是容器的始祖,为什么这么说呢?我们今天就来说一说这个话题。

本文是 Spring 源码解读第七篇,阅读本系列前面文章有助于更好的理解本文:

  1. Spring 源码解读计划
  2. Spring 源码第一篇开整!配置文件是怎么加载的?
  3. Spring 源码第二弹!XML 文件解析流程
  4. Spring 源码第三弹!EntityResolver 是个什么鬼?
  5. Spring 源码第四弹!深入理解 BeanDefinition
  6. 手把手教你搭建 Spring 源码分析环境

1.DefaultListableBeanFactory

要说 XmlBeanFactory 就不得不先说它的父类 DefaultListableBeanFactory,因为 XmlBeanFactory 中的大部分功能实际上在 DefaultListableBeanFactory 中就已经提供好了,XmlBeanFactory 只是对 IO 流的读取做了一些定制而已。

DefaultListableBeanFactory 是一个完整的、功能成熟的 IoC 容器,如果你的需求很简单,甚至可以直接使用 DefaultListableBeanFactory,如果你的需求比较复杂,那么通过扩展 DefaultListableBeanFactory 的功能也可以达到,可以说 DefaultListableBeanFactory 是整个 Spring IoC 容器的始祖。

我们先来看一下 DefaultListableBeanFactory 的继承关系:

从这张类的关系图中可以看出,DefaultListableBeanFactory 实际上也是一个集大成者。在 Spring 中,针对 Bean 的不同操作都有不同的接口进行规范,每个接口都有自己对应的实现,最终在 DefaultListableBeanFactory 中将所有的实现汇聚到一起。从这张类的继承关系图中我们大概就能感受到 Spring 中关于类的设计是多么厉害,代码耦合度非常低。

这些类,在本系列后面的介绍中,大部分都会涉及到,现在我先大概介绍一下每个类的作用,大家先混个脸熟:

  1. BeanFactory:这个接口看名字就知道是一个 Bean 的工厂,BeanFactory 接口定义了各种获取 Bean 的方法、判断 Bean 是否存在、判断 Bean 是否单例等针对 Bean 的基础方法。
  2. ListableBeanFactory:这个接口继承自 BeanFactory,在 BeanFactory 的基础上,扩展了 Bean 的查询方法,例如根据类型获取 BeanNames、根据注解获取 BeanNames、根据 Bean 获取注解等。
  3. AutowireCapableBeanFactory:该接口继承自 BeanFactory,在 BeanFactory 的基础上,提供了 Bean 的创建、配置、注入、销毁等操作。有时候我们需要自己手动注入 Bean 的时候,可以考虑通过实现该接口来完成。AutowireCapableBeanFactory 在 Spring Security 中有一个重要的应用就是 ObjectPostProcessor,这个松哥将在 Spring Security 系列中和大家详细介绍。
  4. HierarchicalBeanFactory:该接口继承自 BeanFactory,并在 BeanFactory 基础上添加了获取 parent beanfactory 的方法。
  5. SingletonBeanRegistry:这个接口定义了对单例 Bean 的定义以及获取方法。
  6. ConfigurableBeanFactory:这个接口主要定了针对 BeanFactory 的各种配置以及销毁的方法。
  7. ConfigurableListableBeanFactory:这是 BeanFactory 的配置清单,这里定义了忽略的类型、接口,通过 Bean 的名称获取 BeanDefinition 、冻结 BeanDefinition 等。
  8. AliasRegistry:这个接口定义了对 alias 的注册、移除、判断以及查询操作。
  9. SimpleAliasRegistry:这个类实现了 AliasRegistry 接口并实现了它里边的方法,SimpleAliasRegistry 使用 ConcurrentHashMap 做载体,实现了对 alias 的注册、移除判断以及查询操作。
  10. DefaultSingletonBeanRegistry:这个类基于 Java 中的集合,对 SingletonBeanRegistry 接口进行了实现。
  11. FactoryBeanRegistrySupport:该类继承自 DefaultSingletonBeanRegistry,并在 DefaultSingletonBeanRegistry 的基础上,增加了获取 FactoryBean 类型、移除 FactoryBean 缓存的方法等等操作。
  12. AbstractBeanFactory:实现了 ConfigurableBeanFactory 接口并继承自 FactoryBeanRegistrySupport,在 AbstractBeanFactory 中对 ConfigurableBeanFactory 中定义的方法进行了实现。
  13. AbstractAutowireCapableBeanFactory:该类继承自 AbstractBeanFactory 并对 AutowireCapableBeanFactory 接口中定义的方法进行了落地实现。
  14. BeanDefinitionRegistry:这个接口继承自 AliasRegistry 接口,并增加了一系列针对 BeanDefinition 的注册、移除、查询、判断等方法。
  15. 最后的 DefaultListableBeanFactory 自然就具备了上面所有的功能。

上面的内容可能看的大家眼花缭乱,松哥这里通过几个简单实际的例子,来带大家使用一下 DefaultListableBeanFactory 的功能,可能大家的理解就比较清晰了。

DefaultListableBeanFactory 作为一个集大成者,提供了非常多的功能,我们一个一个来看。

2.代码改造

首先文章中一开始的三行代码我们可以对其略加改造,因为我们已经说了 XmlBeanFactory 中的大部分功能实际上在 DefaultListableBeanFactory 中就已经提供好了,XmlBeanFactory 只是对 IO 流的读取做了一些定制而已,文件的读取主要是通过 XmlBeanDefinitionReader 来完成的(本系列前面文章已经讲过),我们可以对文章一开始的三行代码进行改造,以便更好的体现“XmlBeanFactory 中的大部分功能实际上在 DefaultListableBeanFactory 中就已经提供好了”:

ClassPathResource res=new ClassPathResource("beans.xml");
DefaultListableBeanFactory factory=new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader=new XmlBeanDefinitionReader(factory);
reader.loadBeanDefinitions(res);
User user = factory.getBean(User.class);
System.out.println("user = " + user);

使用前四行代码代替 XmlBeanFactory,这样 XmlBeanFactory 的功能是不是就很明确了?就是前四行代码的功能。

3.动态注册 Bean

动态注册 Bean,这是 DefaultListableBeanFactory 的功能之一,不过准确来说应该是动态注册 BeanDefinition 。

我们先来看一个简单的例子:

DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory();
GenericBeanDefinition userBeanDefinition = new GenericBeanDefinition();
MutablePropertyValues pvs = new MutablePropertyValues();
pvs.add("username""javaboy");
pvs.add("address""www.javaboy.org");
userBeanDefinition.setPropertyValues(pvs);
userBeanDefinition.setBeanClass(User.class);
defaultListableBeanFactory.registerBeanDefinition("user", userBeanDefinition);
User user = defaultListableBeanFactory.getBean(User.class);
System.out.println("user = " + user);

首先我们自己手动构建一个 DefaultListableBeanFactory 对象。当然也可以使用前面的 XmlBeanFactory。

然后再手动构建一个 GenericBeanDefinition。在前面的文章中,松哥和大家讲过,现在默认使用的 BeanDefinition 就是 GenericBeanDefinition,所以这里我们自己也手动构建一个 GenericBeanDefinition。有了 GenericBeanDefinition 之后,我们设置相关的类和属性。

接下来再将 userBeanDefinition 注册到 defaultListableBeanFactory。注册完成之后,我们就可以从 defaultListableBeanFactory 中获取相应的 Bean 了。

这里说一句题外话,希望大家在阅读本系列每一篇文章的时候,能够将本系列前后文章联系起来一起理解,这样会有很多意料之外的收获。例如上面的,我们既可以声明一个 DefaultListableBeanFactory,也可以声明一个 XmlBeanFactory,那你大概就能据此推断出 XmlBeanFactory 的主要目的可能就是对资源文件进行读取和注册。

那么到底是怎么注册的呢?我们来看一下 defaultListableBeanFactory.registerBeanDefinition 方法的定义:

@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;
    removeManualSingletonName(beanName);
   }
  }
  else {
   // Still in startup registration phase
   this.beanDefinitionMap.put(beanName, beanDefinition);
   this.beanDefinitionNames.add(beanName);
   removeManualSingletonName(beanName);
  }
  this.frozenBeanDefinitionNames = null;
 }
 if (existingDefinition != null || containsSingleton(beanName)) {
  resetBeanDefinition(beanName);
 }
 else if (isConfigurationFrozen()) {
  clearByTypeCache();
 }
}

registerBeanDefinition 方法是在 BeanDefinitionRegistry 接口中声明的,DefaultListableBeanFactory 类实现了 BeanDefinitionRegistry 接口,并实现了该方法,我们来看分析下该方法:

  1. 首先对传入的 beanDefinition 对象进行校验,这也是注册前的最后一次校验,不过这个时候 BeanDefinition 对象已经到手了,所以这个校验并非 XML 文件校验,这里主要是对 methodOverrides 的校验。
  2. 接下来会根据 beanName 从 beanDefinitionMap 中获取 BeanDefinition,看看当前 Bean 是否已经定义过了。beanDefinitionMap 是一个 Map 集合,这个集合中 key 是 beanName,value 是 BeanDefinition 对象。
  3. 如果 BeanDefinition 已经存在了,那么接下来会判断是否允许 BeanDefinition 覆盖,如果不允许,就直接抛出异常(不知道小伙伴们有没有印象,在松哥前面的 OAuth2 系列教程中,经常需要配置允许 BeanDefinition 的覆盖,就是因为这个原因,公众号【江南一点雨】后台回复 OAuth2 获取该教程),如果允许 BeanDefinition 的覆盖,那就向 beanDefinitionMap 中再次存一次值,覆盖之前的值。
  4. 如果 BeanDefinition 不存在,那就直接注册。直接注册分两种情况:项目已经运行了和项目还没运行。
  5. 如果项目已经运行,由于 beanDefinitionMap 是一个全局变量,可能存在并发问题,所以要加锁处理。否则就直接注册,所谓的注册就是把对象存入 beanDefinitionMap 中,同时将 beanName 都存入 beanDefinitionNames 集合中。

这便是 registerBeanDefinition 方法的工作流程。

有小伙伴会说,这个方法从头到尾都是 BeanDefinition,跟 Bean 有什么关系呢?

咋一看确实好像和 Bean 没有直接关系。

其实这涉及到另外一个问题,就是 Bean 的懒加载。这个时候先把 BeanDefinition 定义好,等到真正调用 Bean 的时候,才会去初始化 Bean。我们可以在 User 类的构造方法中打印日志看下,如下:

public class User {
    private String username;
    private String address;

    public User() {
        System.out.println("--------user init--------");
    }

    @Override
    public String toString() {
        return "User{" +
                "username=''" + username + ''\'''' +
                ", address=''" + address + ''\'''' +
                ''}'';
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}

从下图可以看到,当 BeanDefinition 注册完成后,User 并没有初始化,等到 getBean 方法被调用的时候,User 才初始化了。

需要注意的是,我们日常开发中使用的 ApplicationContext 并非懒加载,这个在松哥的 Spring 入门视频中可以看到效果【https://www.bilibili.com/video/BV1Wv41167TU】,具体原理松哥将在本系列后面的文章中和大家分享。

那么如果不想懒加载该怎么办呢?当然有办法。

4.提前注册 Bean

在 DefaultListableBeanFactory 中还有一个 preInstantiateSingletons 方法可以提前注册 Bean,该方法是在 ConfigurableListableBeanFactory 接口中声明的,DefaultListableBeanFactory 类实现了 ConfigurableListableBeanFactory 接口并实现了接口中的方法:

@Override
public void preInstantiateSingletons() throws BeansException {
 if (logger.isTraceEnabled()) {
  logger.trace("Pre-instantiating singletons in " + this);
 }
 // Iterate over a copy to allow for init methods which in turn register new bean definitions.
 // While this may not be part of the regular factory bootstrap, it does otherwise work fine.
 List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
 // Trigger initialization of all non-lazy singleton beans...
 for (String beanName : beanNames) {
  RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
  if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
   if (isFactoryBean(beanName)) {
    Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
    if (bean instanceof FactoryBean) {
     final FactoryBean<?> factory = (FactoryBean<?>) bean;
     boolean isEagerInit;
     if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
      isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
          ((SmartFactoryBean<?>) factory)::isEagerInit,
        getAccessControlContext());
     }
     else {
      isEagerInit = (factory instanceof SmartFactoryBean &&
        ((SmartFactoryBean<?>) factory).isEagerInit());
     }
     if (isEagerInit) {
      getBean(beanName);
     }
    }
   }
   else {
    getBean(beanName);
   }
  }
 }
 // Trigger post-initialization callback for all applicable beans...
 for (String beanName : beanNames) {
  Object singletonInstance = getSingleton(beanName);
  if (singletonInstance instanceof SmartInitializingSingleton) {
   final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
   if (System.getSecurityManager() != null) {
    AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
     smartSingleton.afterSingletonsInstantiated();
     return null;
    }, getAccessControlContext());
   }
   else {
    smartSingleton.afterSingletonsInstantiated();
   }
  }
 }
}

preInstantiateSingletons 方法的整体逻辑比较简单,就是遍历 beanNames,对符合条件的 Bean 进行实例化,而且大家注意,这里所谓的提前初始化其实就是在我们调用 getBean 方法之前,它自己先调用了一下 getBean。

我们可以在案例中手动调用该方法:

DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory();
GenericBeanDefinition userBeanDefinition = new GenericBeanDefinition();
MutablePropertyValues pvs = new MutablePropertyValues();
pvs.add("username""javaboy");
pvs.add("address""www.javaboy.org");
userBeanDefinition.setPropertyValues(pvs);
userBeanDefinition.setBeanClass(User.class);
defaultListableBeanFactory.registerBeanDefinition("user", userBeanDefinition);
defaultListableBeanFactory.preInstantiateSingletons();
User user = defaultListableBeanFactory.getBean(User.class);
System.out.println("user = " + user);

此时在调用 getBean 方法之前,User 就已经初始化了,如下图:

5.getBean

DefaultListableBeanFactory 中另外一个重量级方法就是 getBean 了。不过 getBean 方法的真正实现是在 DefaultListableBeanFactory 的父类 AbstractBeanFactory 中,具体的实现方法是 doGetBean,本来想和大家子在这里聊一聊这个问题,但是发现这是一个非常庞大的问题,BeanFactory 和 FactoryBean 都还没和大家分享,所以这个话题我们还是暂且押后,一个点一个点来。

6.小结

好啦,今天就先说这么多,每篇源码我都尽量配置套一些小案例来演示,这样避免大家看的太枯燥了,我们下周继续~

如果大家觉得有收获,记得点个在看鼓励下松哥哦~


本文分享自微信公众号 - 江南一点雨(a_javaboy)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

DefaultListableBeanFactory

DefaultListableBeanFactory

类结构图
image.png

image.png

DefaultListableBeanFactory 架构图

DefaultListableBeanFactory 架构图

DefaultListableBeanFactory 源码 分析

DefaultListableBeanFactory 源码 分析

1.1 public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException

@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 {
                                //验证beanDefinition
				((AbstractBeanDefinition) beanDefinition).validate();
			}
			catch (BeanDefinitionValidationException ex) {
				throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
						"Validation of bean definition failed", ex);
			}
		}

		BeanDefinition oldBeanDefinition;

		oldBeanDefinition = this.beanDefinitionMap.get(beanName);
		if (oldBeanDefinition != null) {
			if (!isAllowBeanDefinitionOverriding()) {
				throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
						"Cannot register bean definition [" + beanDefinition + "] for bean ''" + beanName +
						"'': There is already [" + oldBeanDefinition + "] bound.");
			}
			else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
				// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
				if (this.logger.isWarnEnabled()) {
					this.logger.warn("Overriding user-defined bean definition for bean ''" + beanName +
							"'' with a framework-generated bean definition: replacing [" +
							oldBeanDefinition + "] with [" + beanDefinition + "]");
				}
			}
			else if (!beanDefinition.equals(oldBeanDefinition)) {
				if (this.logger.isInfoEnabled()) {
					this.logger.info("Overriding bean definition for bean ''" + beanName +
							"'' with a different definition: replacing [" + oldBeanDefinition +
							"] with [" + beanDefinition + "]");
				}
			}
			else {
				if (this.logger.isDebugEnabled()) {
					this.logger.debug("Overriding bean definition for bean ''" + beanName +
							"'' with an equivalent definition: replacing [" + oldBeanDefinition +
							"] with [" + beanDefinition + "]");
				}
			}
			this.beanDefinitionMap.put(beanName, beanDefinition);
		}
		else {
			if (hasBeanCreationStarted()) {//是否已经开始创建bean
				// Cannot modify startup-time collection elements anymore (for stable iteration)
				synchronized (this.beanDefinitionMap) {
					this.beanDefinitionMap.put(beanName, beanDefinition);
					List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);
					updatedDefinitions.addAll(this.beanDefinitionNames);
					updatedDefinitions.add(beanName);
					this.beanDefinitionNames = updatedDefinitions;
					if (this.manualSingletonNames.contains(beanName)) {
						Set<String> updatedSingletons = new LinkedHashSet<String>(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 (oldBeanDefinition != null || containsSingleton(beanName)) {
			resetBeanDefinition(beanName);
		}
	}

 

DefaultListBeanFactory的子类之SimpleAliasRegistry

DefaultListBeanFactory的子类之SimpleAliasRegistry

DefaultListBeanFactory类结构层次图

ClassHierarchy

从继承图看,SimpleAliasRegistry是DefaultListBeanFactory继承类中最底层的实现类。

SimpleAliasRegistry

SimpleAliasRegistry

GitHub: SimpleAliasRegistry.java SimpleAliasRegistryTests.java

SimpleAliasRegistry借助ConcurrentHashMap来做别名的存储,用KEY 存储别名alias,用VALUE 存储别名对应的真名或者别名

1.registerAlias(String name, String alias)

        @Override
	public void registerAlias(String name, String alias) {
		Assert.hasText(name, "''name'' must not be empty");
		Assert.hasText(alias, "''alias'' must not be empty");
		synchronized (this.aliasMap) {
			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)) {
						// 已经存在的别名 - 不需要再次注册,Map中已经有alias->registeredName了且registeredName等于name
						return;
					}
					// 比方说Map中有alias->registeredName了
					// 你现在却要求改为alias->name
					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 + "''");
					}
				}
				// 如果说Map中已经存在name->alias,
				// 那么现在alias->name就是循环引用了
				// 会抛出异常
				checkForAliasCircle(name, alias);
				this.aliasMap.put(alias, name);
				if (logger.isTraceEnabled()) {
					logger.trace("Alias definition ''" + alias + "'' registered for name ''" + name + "''");
				}
			}
		}
	}

checkForAliasCircle(String name, String alias)

检查是不是已经存在name->alias,却还要注册alias->name,这种循环可能会使得其他递归的方法无限循环下去

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");
	}
}

2.hasAlias(String name, String alias)

虽然这 是接口AliasRegistry的方法,但确是SimpleAliasRegister判断name是否包含别名alias的重要方法。采取的方法是先找Map的Value(即先找name),找到name之后可以判断该name对应的registeredAlias是否和参数中的alias相同,如果相同返回true,不相同则递归寻找。

public boolean hasAlias(String name, String alias) {
	for (Map.Entry<String, String> entry : this.aliasMap.entrySet()) {
		String registeredName = entry.getValue();
		if (registeredName.equals(name)) {
			String registeredAlias = entry.getKey();
			if (registeredAlias.equals(alias) || hasAlias(registeredAlias, alias)) 				{
				return true;
			}
		}
	}
	return false;
}

hasAlias方法实现了链式查找别名

SimpleAliasRegistry registry = new SimpleAliasRegistry();
registry.registerAlias("test", "testAlias");
registry.registerAlias("testAlias", "testAlias2");
registry.registerAlias("testAlias2", "testAlias3");

我们可以得到(别名alias,原名name)的对应Map testAlias->test testAlias2->testAlias testAlias3->testAlias2 那么我们就testAlias3->testAlias2->testAlias->test,使用hasAlias寻找的方向与箭头方法相反

再比如


SimpleAliasRegistry registry = new SimpleAliasRegistry();
registry.registerAlias("name", "alias_a");
registry.registerAlias("name", "alias_b");

registry.registerAlias("real_name", "name");

registry.registerAlias("name", "alias_c");
}

alias_abc

这里的每一条连接线+连接线首位两个实体=concurrentHashMap中的一条记录。总共三条别名链,他们分别是 alias_a->name->real_name; alias_b->name->real_name; alias_c->name->real_name; 位于链尾的real_name的就是canonicalName

3.canonicalName(String name)

输入一个name参数(可能是别名alias),查询他的规范名,也就是位于链尾的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;
}

4. getAlias(String name)

public String[] getAliases(String name) {
	List<String> result = new ArrayList<>();
	synchronized (this.aliasMap) {
		retrieveAliases(name, result);
	}
	return StringUtils.toStringArray(result);
}
private void retrieveAliases(String name, List<String> result) {
	this.aliasMap.forEach((alias, registeredName) -> {
		if (registeredName.equals(name)) {
			result.add(alias);
			retrieveAliases(alias, result);
		}
	});
}

lambda 表达式不好懂,咱们再翻译一下

private void retrieveAliases(String name, List<String> result) {
	for (Map.Entry<String, String> entry : aliasMap.entrySet()) {
		String alias = entry.getKey();
		String registeredName = entry.getValue();
		if (registeredName.equals(name)) {
			result.add(alias);
			retrieveAliases(alias, result);
		}
	});
}

从Map中先找匹配的value(name),找到了,就把对应key(alias)添加到列表中,再把key(alias)当成name,继续寻找。举个例子,如果有这样一条别名链 a->b->c->d,那么 getAlias("d") 结果是["c", "b" ,"a"] getAlias("c") 结果是["b" ,"a"] getAlias("b") 结果是["a"] getAlias("a") 结果是[]

5.resolveAliases(StringValueResolver valueResolver

这个方法和registerAlias(String name, String alias)相似度极高。 在执行resolveAliases之前,aliasMap中存储的是(别名alias,别名目标名称registeredName),运用值解析器解析之后,别名alias将被替换为resolvedAlias,

/**
 * 解析在此工厂中注册的所有别名目标名称和别名,并将给定的
 * StringValueResolver应用于它们。
 * 例如,值解析器可以解析目标bean名称中的占位符,甚至可以
 * 解析别名中的占位符。
 */
public void resolveAliases(StringValueResolver valueResolver) {
	Assert.notNull(valueResolver, "StringValueResolver must not be null");
	synchronized (this.aliasMap) {
		// 拷贝一份aliasMap,这样就可以再遍历aliasMap副本时,修改原aliasMap
		Map<String, String> aliasCopy = new HashMap<>(this.aliasMap);
		aliasCopy.forEach((alias, registeredName) -> {
			// 
			String resolvedAlias = valueResolver.resolveStringValue(alias);
			String resolvedName = valueResolver.resolveStringValue(registeredName);
			// (情况零)
			// 如果解析出的别名或者解析出的目标名称为null,亦或者两者相同,则移除alias->registeredName
			if (resolvedAlias == null || resolvedName == null || resolvedAlias.equals(resolvedName)) {
				this.aliasMap.remove(alias);
			}
			else if (!resolvedAlias.equals(alias)) {
				// 如果已解析的别名resolvedAlias不等于alias
				String existingName = this.aliasMap.get(resolvedAlias);
				if (existingName != null) {
					if (existingName.equals(resolvedName)) {
						// (情况二)
						// 指向现有别名,只需要删除占位符
						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)) {
				// (情况三)
				// 如果已解析的别名resolvedAlias等于alias
				// 但是已解析的注册名resolvedName不等于原注册名registeredName
				// 则使用已解析的注册名resolvedName覆盖原注册名registeredName
				// alias->resolvedName
				this.aliasMap.put(alias, resolvedName);
			}
		});
	}
}

情况一

  • 假如alias不等于resolvedAlias,且resolvedAlias->existingName不存在。那么,移除alias->resigteredName,新增resolvedAlias->resolvedName 情况一

情况二

  • 假如alias不等于resolvedAlias,且resolvedAlias->existingName已经存在,那么移除alias->resigteredName 情况二

情况三

  • 假如alias等于resolvedAlias,且resolvedName不等于registeredName。那么,用resolvedAlias/alias->resolvedName覆盖alias->resigteredName

  • StringValueResolver的结构图: StringValueResolver

  • StringValueResolver的主要接口方法 String resolveStringValue(String strVal),其作用是解析给定的String值,例如解析占位符

我们今天的关于Spring 源码第六弹!松哥和大家聊聊容器的始祖 DefaultListableBeanFactoryspring容器原理的分享已经告一段落,感谢您的关注,如果您想了解更多关于DefaultListableBeanFactory、DefaultListableBeanFactory 架构图、DefaultListableBeanFactory 源码 分析、DefaultListBeanFactory的子类之SimpleAliasRegistry的相关信息,请在本站查询。

本文标签:

上一篇兖州网站seo(兖州门户网)(兖州在线网)

下一篇20 个最有用的免费 Web 图标集(免费的图标网站)