【Spring源码研究】- 你不得不知的六大接口

BeanFactory,FactoryBean,BeanFactoryPostProcessor, BeanPostProcessor, BeanDefinitionReader, Environment

1.BeanDefinitionReader

BeanDefinitionReader 是一个接口,从字面意思可以看出,这是一个定义了 Bean 定义信息加载规范的接口,那么在这里我会从三个方向来研究 BeanDefinitionReader 接口,分别是:(1) BeanDefinitionReader 加载 Bean 定义信息需要些什么?(2) BeanDefinitionReader 是如何加载 Bean 定义信息的? (3) BeanDefinitionReader 加载的 Bean 定义信息去了哪里?

在解答这三个问题之前,我们先来研究一下 BeanDefinitionReader 接口的源码。

接口:BeanDefinitionReader 位置:org.springframework.beans.factory.support 版本:5.3.12

public interface BeanDefinitionReader {
    /*
    *返回一个可注册 BeanDefinition 的工厂
    * BeanDefinitionRegistry:
    * 1. registerBeanDefinition(...):注册 BeanDefinition
    * 2. removeBeanDefinition(...):移除 BeanDefinition
    * 3. getBeanDefinition(...):获取 BeanDefinition
    * 4. isBeanNameInUse(...):当前 Bean 的名称是否被使用
    */
	BeanDefinitionRegistry getRegistry();
    
    /**
    * 获取资源加载器,主要就是根据路径和ClassLoader获取Resource,之后通过Resource获取输入流读取文件
    */
	@Nullable
	ResourceLoader getResourceLoader();

    /**
    * 获取 Bean 的类加载器
    */
	@Nullable
	ClassLoader getBeanClassLoader();
    
    /**
    * 返回一个 Bean 的名字生成器,为匿名 Bean 生成一个名字,就是唯一区别的 id
    */
	BeanNameGenerator getBeanNameGenerator();

    /**
    * 从指定资源加载 BeanDefinition
    */
	int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException;

    /**
    * 从指定资源加载 BeanDefinition
    */
	int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException;

    /**
    * 从指定位置的资源加载 BeanDefinition
    */
	int loadBeanDefinitions(String location) throws BeanDefinitionStoreException;

    /**
    * 从指定位置的资源加载 BeanDefinition,如从那个文件加载等
    */
	int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException;

由 BeanDefinitionReader 的源码可以得出:

(1).BeanDefinitionReader 加载 Bean 定义信息需要 一个资源加载器 ResourceLoader ,一个类加载器 ClassLoader ,一个 Bean 名字的生成器 BeanNameGenerator。

(2).BeanDefinitionReader 对于不同的资源文件有不同的资源加载器的实现,如 xml 文件对应 ClassPathXmlApplicationContext,注解对应 AnnotationConfigApplicationContext 等等;BeanDefinitionReader 通过相应的资源加载器和类加载器通过 loadBeanDefinitions(…) 方法来加载 BeanDefinition。

(3).BeanDefinitionReader 会将加载进来的 BeanDefinition 注册到通过 getRegistry() 方法获取到的工厂中。这里以加载 xml 资源文件为例:其具体实现是在 DefaultBeanDefinitionDocumentReader#processBeanDefinition(…) 方法中。

2.Environment

对于这个接口其实最重要的还是其实现类 StandardEnvironment ,此类用于加载程序运行的所有环境变量,包括操作系统与 jvm 的可运行的环境变量

StandardEnvironment 接口的源码如下:

类:StandardEnvironment 位置:org.springframework.core.env 版本:5.3.12

public class StandardEnvironment extends AbstractEnvironment {

	/**
	* 系统环境属性源名称:“systemEnvironment”
	*/
	public static final String SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME = "systemEnvironment";

	/**
	* JVM 系统属性属性源名称:“SystemProperties”
	*/
	public static final String SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME = "systemProperties";


    /**
    * 让使用适合任何标准 Java 环境的人自定义属性来源集
    * 这里其实会加载机器上所有的可运行环境,如 java, jre等等
    */
	@Override
	protected void customizePropertySources(MutablePropertySources propertySources) {
		propertySources.addLast(new MapPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));
		propertySources.addLast(new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));
	}

}

在 Spring IOC 容器初始化阶段会使用到此类:

使用位置为 AbstractApplicationContext#refresh() 方法中的第一步:准备上下文用以进行刷新 —》prepareRefresh();

3.BeanFactory

源码:

接口:BeanFactory 位置:org.springframework.beans.factory 版本号:5.3.12

public interface BeanFactory {

    /**
    * 这个符号是用于取消引用 FactoryBean 实例并将 bean 工厂与 FactoryBean 创建的实例区分开
    * 此符号可详见 FactoryBean 接口,
    * 对于一个实现了 FactoryBean 接口的类,例:MyObject
    * 通过 myObject 名称获取的是 FactoryBean 的 getObject() 方法返回的对象实例
    * 通过 &myObject 名称获取的是 MyObject 这个工厂 Bean 的实例, 即他本身
    **/
	String FACTORY_BEAN_PREFIX = "&";

    /**
    * 通过给定的 bean 名称 获取 Bean 对象实例
    **/
	Object getBean(String name) throws BeansException;
    
    /**
    * 通过给定的 bean 名称 获取 Bean 对象实例,但此处会有一个类型检测,如果通过 指定 bean 
    * 名称获取到的对象实例的类型与 requiredType 不一致,就会抛出 BeanNotOfRequiredTypeException 
    * 相当于类型检查
    **/
	<T> T getBean(String name, Class<T> requiredType) throws BeansException;

    /**
    * 通过给定的 bean 名称获取 bean 对象实例,允许指定显式构造方法的参数/工厂方法的参数,覆盖 bean 定义中指定的默认参数
    * 这里的 args 只是在创建新实例的时候才会使用,因为他是用来替换 bean 定义中指定的默认参数
    **/
	Object getBean(String name, Object... args) throws BeansException;

    /**
    * 获取与给定的 requiredType 类型一致的对象实例
    * 此方法会去 ListableBeanFactory 中按类型查找
    * 参考: DefaultListableBeanFactory#getBean(Class<T> requiredType)方法
    **/
	<T> T getBean(Class<T> requiredType) throws BeansException;

    /**
    * 看参数就知道这方法就是:获取 bean 对象实例,允许指定显式构造方法的参数/工厂方法的参数,
    * 覆盖 bean 定义中指定的默认参数,并获取与给定的 requiredType 类型一致的对象实例
    * 记录:对于 bean 实例的获取:按名称 ,按类型(涉及到通过类型查找,跨 Bean 集查找,按名称查找并校验类型多种方式)
    **/
	<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 定义或者外部注册的单例实例
    * 注意:此方法返回 true 并不代表通过 getBean() 方法能获取到对应名称的 bean 实例
    * 因为他会去当前工厂或者其所有父工厂寻找符合名称的已创建,正在创建,懒加载的,急切加载的,凡是范围内的 bean 实例
    * 这样有可能其返回 true 时 bean 实例还没创建好
    **/
	boolean containsBean(String name);

    /**
    * 判断 bean 实例是否是单例的,
    * 但其返回 false 并不能表示当前 bean 实例是原型的,只能表示当前 bean 实例是非单例的
    **/
	boolean isSingleton(String name) throws NoSuchBeanDefinitionException;

    /**
    * 判断当前 bean 实例是否是原型的,
    * 但其返回 false 并不能表示当前 bean 实例是单例的,只能表示当前 bean 实例是非原型的
    **/
	boolean isPrototype(String name) throws NoSuchBeanDefinitionException;

    /**
    * 判断给定名称的 bean 的类型是否与指定类型一致
    **/
	boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;

    /**
    * 判断给定名称的 bean 的类型是否与指定类型一致
    **/
	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 的别名,
    * 如果给定的名称是别名,则会返回该 bean 的原名称以及别名,数组中的第一个放的是原名称
    **/
	String[] getAliases(String name);
}

BeanFactory 接口是一个访问 Spring Bean 容器的一个跟接口。

通常我们会将 BeanFactory 称作 bean 工厂,其含义是用来 实例化、定位、配置应用程序中的对象及建立这些对象间的依赖

4.FactoryBean

源码:

接口:FactoryBean 位置:org.springframework.beans.factory 版本:5.3.12

public interface FactoryBean<T> {

    /**
    * 可以设置在 BeanDefinition 上的属性的名称,
    * 以便工厂 bean 可以在无法从工厂 bean 类中推断出它们的对象类型时可以返回一个默认的类型。(描述不太准确,没找到相关案例)
    **/
	String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";

    /**
    * 返回此工厂管理的对象的实例
    * 这个方法极为重要: 此方法就是我们自定义对象实现的地方
    */
	@Nullable
	T getObject() throws Exception;

    /**
    * 返回此 FactoryBean 创建的对象类型,如果事先未知,则返回null 。
    * 这允许人们在不实例化对象的情况下检查特定类型的 bean,例如在自动装配时。
	* 在创建单例对象的实现的情况下,此方法应尽量避免创建单例; 它应该提前估计类型。 
	* 对于原型,也建议在此处返回有意义的类型。
    **/
	@Nullable
	Class<?> getObjectType();
    
	default boolean isSingleton() {
		return true;
	}
}

作用:用来实现复杂的 bean

实现了 FactoryBean 接口的类其本身就是一个 bean,其实与 BeanFactory 的联系就在于 FactoryBean 也可以看成是一个工厂,他也可以管理生成 bean

5.BeanFactoryPostProcessor

源码:

接口:BeanFactoryPostProcessor 位置:org.springframework.beans.factory.config 版本:5.3.12

@FunctionalInterface
public interface BeanFactoryPostProcessor {

	/**
	 * 在标准初始化之后修改应用程序上下文的内部 bean 工厂。 
	 * 所有 bean 定义都将被加载,但尚未实例化任何 bean。 这甚至允许覆盖或添加属性,甚至是急切初始化的 bean
	 */
	void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

}

通过名字便可知这是一个后置处理器,用于对加载到工厂中的 BeanDefinition 做修改,但前提是这些 bean 还没有初始化。有点类似于 AOP,是 Spring 为了方便开发者二次开发定义的标准接口。功能强大。

6.BeanPostProcessor

源码:

接口:BeanPostProcessor 位置:org.springframework.beans.factory.config 版本:5.3.12

public interface BeanPostProcessor {

	/**
	 * 实例化、依赖注入完毕,在调用显示的初始化之前完成一些定制的初始化任务
	 */
	@Nullable
	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

	/**
	 * 实例化、依赖注入、初始化完毕时执行
	 */
	@Nullable
	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

}

作用是在Bean对象在实例化和依赖注入完毕后,在显示调用初始化方法的前后添加我们自己的逻辑。注意是Bean实例化完毕后及依赖注入完成后触发的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值