Spring 源码第六弹!容器的始祖 DefaultListableBeanFactory

Spring 源码继续开整!java

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

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

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 源码解读第七篇,阅读本系列前面文章有助于更好的理解本文:app

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

1.DefaultListableBeanFactory

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

DefaultListableBeanFactory 是一个完整的、功能成熟的 IoC 容器,若是你的需求很简单,甚至能够直接使用 DefaultListableBeanFactory,若是你的需求比较复杂,那么经过扩展 DefaultListableBeanFactory 的功能也能够达到,能够说 DefaultListableBeanFactory 是整个 Spring IoC 容器的始祖。源码分析

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

从这张类的关系图中能够看出,DefaultListableBeanFactory 实际上也是一个集大成者。在 Spring 中,针对 Bean 的不一样操做都有不一样的接口进行规范,每一个接口都有本身对应的实现,最终在 DefaultListableBeanFactory 中将全部的实现汇聚到一块儿。从这张类的继承关系图中咱们大概就能感觉到 Spring 中关于类的设计是多么厉害,代码耦合度很是低。ui

这些类,在本系列后面的介绍中,大部分都会涉及到,如今我先大概介绍一下每一个类的做用,你们先混个脸熟:this

  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 入门视频中能够看到效果【www.bilibili.com/video/BV1Wv…】,具体原理松哥将在本系列后面的文章中和你们分享。

那么若是不想懒加载该怎么办呢?固然有办法。

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.小结

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

若是你们以为有收获,记得点个在看鼓励下松哥哦~

相关文章
相关标签/搜索