欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Spring框架源码分析(IoC):BeanFactory和ApplicationContext容器家族

程序员文章站 2022-07-12 13:35:18
...

前置知识

组件扫描:自动发现应用容器中需要创建的Bean。
自动装配:自动满足Bean之间的依赖。

BeanFactory:Spring容器的基石,*容器接口

在第一个章节中,我们提到过,在Spring官方文档中,称org.springframework.context.ApplicationContext这个接口就代表了Spring的容器,在解释ApplicationContext之前,必须要先介绍Spring容器的基石,BeanFactory接口。ApplicationContext就是继承了BeanFactory接口的一种高级容器接口。而BeanFactory是简单容器的代表,是Spring容器家族的基石,所有的容器都必须实现这个接口。

首先,先看一下BeanFactory接口的源码。

package org.springframework.beans.factory;

public interface BeanFactory {
	/**
	 * 对FactoryBean的转移定义,提供获取FactoryBean实例的方法。
	 * 如果定义bean时是通过工厂模式配置Bean的,那么通过bean的名字检索FactoryBean时
	 * 得到的会是FactoryBean生产出来的实例,如果想得到工厂本身,需要进行转义
	 */
	String FACTORY_BEAN_PREFIX = "&";

	/**
	 * 不同的获取Bean的方法
	 */
	Object getBean(String name) throws BeansException;
	<T> T getBean(String name, Class<T> requiredType) throws BeansException;
	Object getBean(String name, Object... args) throws BeansException;
	<T> T getBean(Class<T> requiredType) throws BeansException;
	<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;

	/**
	 * 获取Bean的提供者(工厂)
	 */
	<T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);
	<T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);
	
	// 检索是否包含指定名字的bean
	boolean containsBean(String name);
	// 判断指定名字的bean是否为单例
	boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
	// 判断指定名字的bean是否为原型
	boolean isPrototype(String name) throws NoSuchBeanDefinitionException;

	/**
	 * 指定名字的Bean是否匹配指定的类型
	 */
	boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
	boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;

	/**
	 * 获取指定名字的Bean的类型
	 */
	@Nullable
	Class<?> getType(String name) throws NoSuchBeanDefinitionException;
	@Nullable
	Class<?> getType(String name, boolean allowFactoryBeanInit) throws NoSuchBeanDefinitionException;

	// 获取指定名字Bean的所有别名
	String[] getAliases(String name);
}

可以看出,BeanFactory接口的源码并不复杂,主要规定了一些容器的基本功能,其中有7个获取Bean或者Bean提供者的方法,5个判断型的方法,2个获取类型的方法,1个获取别名的方法。通过这些方法,可以看出BeanFactory是一个典型的工厂模式的工厂接口。

在之前的文章中我们提到过:Spring框架的设计中,充满了通过上下继承关系来对基类进行功能扩充与功能分隔的类体系。 BeanFactory体系也是如此。

下面看一下在*容器接口的下面,Spring又做了哪些骚操作吧:

Spring框架源码分析(IoC):BeanFactory和ApplicationContext容器家族
BeanFactory家族的核心成员主要就是上面的几个,其关系类图如图所示,BeanFactory位于家族顶层。这些接口和实现类,每一个都代表了对BeanFactory不同方向的功能扩展,下面逐一进行分析。

*二级接口ListableBeanFactoryHierarchicalBeanFactroy

  • ListableBeanFactory:该接口拥有列出工厂中所有Bean的能力。
public interface ListableBeanFactory extends BeanFactory {
	
	// 检索是否包含给定beanName的BeanDefinition
	boolean containsBeanDefinition(String beanName);
	// 获取工厂中BeanDefinition的数量
	int getBeanDefinitionCount();
	// 获取工厂中所有BeanDefinition的Names
	String[] getBeanDefinitionNames();
	// 获取指定类型的beanNames
	String[] getBeanNamesForType(ResolvableType type);
	String[] getBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit);
	String[] getBeanNamesForType(@Nullable Class<?> type);
	String[] getBeanNamesForType(@Nullable Class<?> type, boolean includeNonSingletons, boolean allowEagerInit);
	// 根据指定的类型来获取所有Bean
	<T> Map<String, T> getBeansOfType(@Nullable Class<T> type) throws BeansException;
	<T> Map<String, T> getBeansOfType(@Nullable Class<T> type, boolean includeNonSingletons, boolean allowEagerInit)
			throws BeansException;
	// 根据指定的直接获取beanNames
	String[] getBeanNamesForAnnotation(Class<? extends Annotation> annotationType);
	// 获取所有指定注解标注的Bean实例,Autowired就是使用的该接口
	Map<String, Object> getBeansWithAnnotation(Class<? extends Annotation> annotationType) throws BeansException;
	// 查找指定Bean中含有的注解类型
	@Nullable
	<A extends Annotation> A findAnnotationOnBean(String beanName, Class<A> annotationType)
			throws NoSuchBeanDefinitionException;

}

可以看出ListableBeanFactory主要对外提供了批量获取Bean和BeanDefinition的方法,拓展类了BeanFactory的功能,是一个非常重要的接口。

  • HierarchicalBeanFactroy接口:顾名思义,这是一个分层的工厂。该接口实现了Bean工厂的分层。
public interface HierarchicalBeanFactory extends BeanFactory {

	/**
	 * 返回父级工厂
	 */
	@Nullable
	BeanFactory getParentBeanFactory();

	/**
	 * 检索本地工厂是否包含指定名字的Bean
	 */
	boolean containsLocalBean(String name);

}

这个接口非常简单,也是继承自BeanFactory,虽然简单,但却提供了一个非常重要的功能——工厂分层。工厂分层有什么用呢?通过工厂分层,SpringIoC容器可以建立父子层级关联的容器体系,子容器可以访问父容器中的Bean,而父容器不能访问子容器中的Bean。在容器内,Bean的id必须是唯一的,但子容器可以拥有一个和父容器id相同的Bean。

父子容器层级体系增强了Spring容器架构的扩展性和灵活性,因为第三方可以通过编程的方式,为一个已经存在的容器添加一个或多个特殊用途的子容器,以提供一些额外的功能。

Spring使用父子容器实现了很多功能,比如在Spring MVC中,展现层Bean位于一个子容器中,而业务层和持久层的Bean位于父容器中。这样,展现层Bean就可以引用业务层和持久层的Bean,而业务层和持久层的Bean则看不到展现层的Bean。

复杂配置的Bean工厂ConfigurableBeanFactory接口

ConfigurableBeanFactory接口是一个继承了HierarchicalBeanFactroy的子接口,同时该接口还继承了SingletonBeanRegistry接口,SingletonBeanRegistry是一个用来注册单例类的接口,提供了同意访问单例Bean的功能,该接口的方法如下图:
Spring框架源码分析(IoC):BeanFactory和ApplicationContext容器家族
也就是说ConfigurableBeanFactory同时拥有了工厂分层和单例注册的功能,并且为了不辜负ConfigurableBeanFactory这个名字,该接口又继续扩展了几十个方法!加上继承来的方法,这个接口中的方法数量非常之多。
Spring框架源码分析(IoC):BeanFactory和ApplicationContext容器家族
该接口主要扩展了一些复杂的对单例Bean的配置与操作,虽然这个接口并没有被ApplicationContext高级容器体系所继承,但是一般的容器实现类都会继承或实现这个接口,目的是使用一种统一的方式对外暴露管理单例Bean的方式。

自动装配工厂:AutowireCapableBeanFactory接口

该接口直接继承自BeanFactory接口,扩展出了工厂的自动装配功能,其提供的方法如下:
Spring框架源码分析(IoC):BeanFactory和ApplicationContext容器家族
该接口主要作用是将自动装配的能力对外暴露出来,可以通过实现此接口实现自动装配能力,但是正常情况下不应该使用该接口。此接口主要针对框架之外,没有向Spring托管的Bean的应用。其中比较重要的知识是四种自动装配策略:

	// 用于表示外部自动装配功能是否可用,但是不影响自动装配功能的使用
	int AUTOWIRE_NO = 0;
	// 标识 按名称自动装配
	int AUTOWIRE_BY_NAME = 1;
	// 标识 按类型自动装配 Autowired默认使用的该装配策略
	int AUTOWIRE_BY_TYPE = 2;
	// 标识 按照贪婪策略匹配到的最合适构造器来自动装配
	int AUTOWIRE_CONSTRUCTOR = 3;

Bean工厂接口的集大成者:ConfigurableListableBeanFactory 接口

此工厂接口看类名即可知道,是一个继承了ListableBeanFactoryConfigurableBeanFactory接口的子接口,同时它还继承了AutowireCapableBeanFactory接口,并且自身还扩展了一些功能,加在一起,这个接口的方法大概有接近100之巨。该接口总体上是继承多种父接口,并对功能进行略微扩展补充,包含了BeanFactory接口体系目前的所有方法,是Bean工厂接口的集大成者。
Spring框架源码分析(IoC):BeanFactory和ApplicationContext容器家族
Spring框架源码分析(IoC):BeanFactory和ApplicationContext容器家族

额外的知识

BeanFactroy和ApplicationContext的区别

BeanFactory和FactoryBean的区别