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实例化完毕后及依赖注入完成后触发的。