【Spring源码分析】BeanFactory系列接口解读

news/2024/11/19 14:41:10/

认识Bean工厂

  • 一、认识Bean工厂
    • BeanFactory
    • ListableBeanFactory
    • HierarchicalBeanFactory
    • AutowireCapableBeanFactory
    • ConfigurableBeanFactory
    • ConfigurableListableBeanFactory
  • 二、总结

一、认识Bean工厂

Spring Bean 工厂是Spring框架提供的一种机制,用于创建和管理对象(或称为Bean)。它是Spring框架的核心部分,提供了一种灵活、可配置的方式来管理对象的生命周期和依赖关系

下面展示了整个 Bean 工厂的常见接口和类以及功能(其中 XmlBeanFactory 已经被弃用):

1671758309265

1、不同的接口展现了不同的能力,是对子类能力的抽象;

2、 抽象类构建通用方法的实现,是通用核心方法的具体实现;

3、 具体类完成特定功能的实现,是特定功能的具体实现;

BeanFactory

public interface BeanFactory {// 这个变量在获取一个 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;// 返回对应的 ObjectProvider,这是一种可以延迟获取 bean 实例的模式// 比如基于 ObjectProvider#getIfUnique 方法获取实例(获取容器中的对象)<T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);<T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);// 判断是否包含指定 name 的 bean Definition 或 单例// 此处返回 true 并不意味着 getBean 可以返回对应的实例boolean containsBean(String name);// 判断 name 对应的 bean 是否是单例boolean isSingleton(String name) throws NoSuchBeanDefinitionException;// 判断 name 对应的 bean 是否是原型(prototype)boolean isPrototype(String name) throws NoSuchBeanDefinitionException;// 判断指定 name 的bean是否匹配对应的类型boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;// 获取 name 对应的 bean 的类型@NullableClass<?> getType(String name) throws NoSuchBeanDefinitionException;@NullableClass<?> getType(String name, boolean allowFactoryBeanInit) throws NoSuchBeanDefinitionException;// 返回指定 name 的所有别名String[] getAliases(String name);}

在 Spring4.3 之前,我们的bean如果需要使用特定构造器进行构造时必须使用@Autowired注解:

@Service
public class UserService {private UserDao userDao;@Autowiredpublic UserService(UserDao userDao) {this.userDao = userDao;}
}

在 Spring4.3 之后,如果没有其他构造器(有无参构造默认会使用无参构造,当然如果无参也没有,还有多个有参),会隐式为其注入:

@Service
public class UserService {UserDao userDao;public UserService(UserDao userDao) {this.userDao = userDao;}
}

但是当容器中没有 UserDao 这个 Bean 的时候,就会报以下异常:

在这里插入图片描述

此时 ObjectProvider 就提供了它的作用了:

@Service
public class UserService {UserDao userDao;public UserService(ObjectProvider<UserDao> objectProvider) {// 如果容器中存在就返回,不存在返回nullthis.userDao = objectProvider.getIfUnique();}}

在这里插入图片描述

这样注入的好处很明显,就是如果容器中不存在 UserDao 或者存在多个 UserDao 时,可以从容处理。

ObjectProvider 接口如下,他继承自 ObjectFactory,这个接口后边也会常用:

public interface ObjectProvider<T> extends ObjectFactory<T>, Iterable<T> {T getObject(Object... args) throws BeansException;// 处理判断有可用的bean的时候我们怎么做,可以重写T getIfAvailable() throws BeansException;default T getIfAvailable(Supplier<T> defaultSupplier) throws BeansException {T dependency = getIfAvailable();return (dependency != null ? dependency : defaultSupplier.get());}default void ifAvailable(Consumer<T> dependencyConsumer) throws BeansException {T dependency = getIfAvailable();if (dependency != null) {dependencyConsumer.accept(dependency);}}// 处理判断只有唯一的bean的时候我们怎么做,可以重写T getIfUnique() throws BeansException;default T getIfUnique(Supplier<T> defaultSupplier) throws BeansException {T dependency = getIfUnique();return (dependency != null ? dependency : defaultSupplier.get());}default void ifUnique(Consumer<T> dependencyConsumer) throws BeansException {T dependency = getIfUnique();if (dependency != null) {dependencyConsumer.accept(dependency);}}// 当匹配多个时,可以迭代处理@Overridedefault Iterator<T> iterator() {return stream().iterator();}
}

ObjectFactory 作为一个对象工厂函数式接口更是简单:

@FunctionalInterface
public interface ObjectFactory<T> {/*** Return an instance (possibly shared or independent)* of the object managed by this factory.* @return the resulting instance* @throws BeansException in case of creation errors*/T getObject() throws BeansException;}

ListableBeanFactory

该工厂继承自 BeanFactory,在含有Bean基础功能的基础上,提供了更强的枚举能力。ListableBeanFactory 为后续的实现类提供了更强的枚举能力,这些能力可能不对外公开,但是对于子类操作容器的操作bean十分重要,下面是他提供的方法:

public interface ListableBeanFactory extends BeanFactory {// 对BeanDefinition的一些细节操作boolean containsBeanDefinition(String beanName);int getBeanDefinitionCount();String[] getBeanDefinitionNames();// 对 BeanFactory 中获取ObjectProvider方法的拓展<T> ObjectProvider<T> getBeanProvider(Class<T> requiredType, boolean allowEagerInit);<T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType, boolean allowEagerInit);// 获取指定类型(子类)的bean names// boolean includeNonSingletons 参数决定是否考虑 singleotn 以外的bean// boolean allowEagerInit 是否初始化对应FactoryBean,如果false则类型直接匹配对应的FactoryBeanString[] 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);/**基本同上,返回的 Map 结构k:beanNamev:beanInstance**/<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;// 返回指定注解的beanName数组String[] getBeanNamesForAnnotation(Class<? extends Annotation> annotationType);// 返回指定注解的bean实例集合:beanName -> bean 实例Map<String, Object> getBeansWithAnnotation(Class<? extends Annotation> annotationType) throws BeansException;// 获取指定 beanName 上的注解// 同样涉及 FactoryBean 初始化的问题,由参数 allowFactoryBeanInit 决定@Nullable<A extends Annotation> A findAnnotationOnBean(String beanName, Class<A> annotationType)throws NoSuchBeanDefinitionException;@Nullable<A extends Annotation> A findAnnotationOnBean(String beanName, Class<A> annotationType, boolean allowFactoryBeanInit)throws NoSuchBeanDefinitionException;<A extends Annotation> Set<A> findAllAnnotationsOnBean(String beanName, Class<A> annotationType, boolean allowFactoryBeanInit)throws NoSuchBeanDefinitionException;
}    

BeanFactory 的子接口:

  • 拓展了枚举的能力,提供了多个枚举的方法;
  • 这些方法都仅限于当前层级的枚举,如果需要考虑到父级,可以借助 BeanFactoryUtils.
  • containsBeanDefinition、getBeanDefinitionCount、getBeanDefinitionNames 这几个方法是完全基于当前 BeanFactory 中的 BeanDefinition 的,换句话说,对于通过 registerSingleton 等方法注册的 bean 实例,它们是不感知的
  • getBeanNamesForType、getBeansOfType 方法是会感知自行注册 bean 实例的,当然大多数场景的 bean 实例都是基于 BeanDefinition 扫描的。

HierarchicalBeanFactory

HierarchicalBeanFactory 为 bean 工厂提供了灵活的分层能力,这在 web 工程里由典型的应用,spring 和 springmvc 会建立两个独立的上下文,分层之后各司其职,更易管理

public interface HierarchicalBeanFactory extends BeanFactory {// 返回 bean 工厂的父工厂@NullableBeanFactory getParentBeanFactory();// 此方法忽略祖先上下文定义的bean,只会查询本地工厂boolean containsLocalBean(String name);}

测试一手:

	@Testpublic void testHierarchicalBeanFactory() {// 创建一个核心工厂DefaultListableBeanFactory parent = new DefaultListableBeanFactory();parent.registerSingleton("person1", new Person("张三", 18));// 创建一个子工厂工厂,独自管理各个层次的内容DefaultListableBeanFactory child = new DefaultListableBeanFactory();// 设置父子关联关系child.setParentBeanFactory(parent);// 子工厂可以访问父工厂的beanlog.info("{}", child.getBean("person1"));log.info("{}", child.containsBean("person1"));// containsLocalBean()方法判断当前工厂是否包含指定的bean,如果是,则返回true,否则返回falselog.info("{}", child.containsLocalBean("person1"));}

BeanFactory 的 子接口:

  • 提供了层次关系维护,getParentBeanFactory 用于获取父 BeanFactory
  • containsLocalBean 不同于 BeanFactory#containsBean,只会在当前层级中判断是否存在指定 namebean实例.

AutowireCapableBeanFactory

这个接口提供了构建和自动装配的能力,主要是赋予子类自动装配的能力,是容器最核心的接口,这个接口定义了 bean 的创建以及装配能力,同时细粒度的控制了 bean 的生命周期

public interface AutowireCapableBeanFactory extends BeanFactory {// 表示不进行自动注入,默认情况下都是该状态// 真正的注入,一般都是基于 @Autowire 等注解驱动int AUTOWIRE_NO = 0;// 基于属性 name 的自动注入模式,一般不用int AUTOWIRE_BY_NAME = 1;// 基于属性 type 的自动注入模式,@Bean 方式就是这种模式int AUTOWIRE_BY_TYPE = 2;// 基于构造方法的自动注入,一般不用int AUTOWIRE_CONSTRUCTOR = 3;// 通过此后缀获取原始实例(比如 代理实例的 target)String ORIGINAL_INSTANCE_SUFFIX = ".ORIGINAL";// 创建实例的典型方法<T> T createBean(Class<T> beanClass) throws BeansException;// 自动填充指定 bean  实例属性,本质上是 after-instantiation 和 property post-processing 回调的执行void autowireBean(Object existingBean) throws BeansException;// 配置给定 bean 实例,本质是属性填充以及初始化回调的执行Object configureBean(Object existingBean, String beanName) throws BeansException;//--------------------------------------------------------------------// 用于对bean生命周期进行细粒度控制的专门方法// 主要是三块内容:创建(实例化) 属性填充(装配) 初始化//--------------------------------------------------------------------/**生命周期第一步(创建)按照指定的装配策略根据class生成一个完整的bean的实例执行bean的完全初始化,包括所有适用的beanpostprocessors@param dependencyCheck 是否对对象执行依赖项检查(不适用于自动装配构造函数,因此忽略)@return 新的bean的实例**/Object createBean(Class<?> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException;/**生命周期第二步(装配)基于 autowireMode 创建 bean 实例并自动填充通过应用 after-instantiation 和 property post-processing(例如注解驱动的注入)来填充给定的bean实例**/Object autowire(Class<?> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException;/*** 基于 autowireMode 自动填充已经存在的 bean 实例* 已经存在的实例不支持 AUTOWIRE_CONSTRUCTOR */void autowireBeanProperties(Object existingBean, int autowireMode, boolean dependencyCheck)throws BeansException;/*** 基于 BeanDefinition 的属性填充已存在的 bean 实例*/void applyBeanPropertyValues(Object existingBean, String beanName) throws BeansException;// 初始化前的回调// 将 BeanPostProcessors 应用到给定的现有bean实例// 调用它们的postprocessBeforeInitialization方法Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)throws BeansException;// 初始化给定的原始 bean,应用工厂回调,如setBeanName和setBeanFactory// 当然也包括应用所有的bean postprocessorsObject initializeBean(Object existingBean, String beanName) throws BeansException;// 初始化后置处理Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)throws BeansException;// 销毁给定的bean实例// 使用DisposableBean接口定义的销毁方法void destroyBean(Object existingBean);//-------------------------------------------------------------------------// 解决匹配注入点的方法// 在注入的时候通过以下的方法匹配属性与之对应的bean//-------------------------------------------------------------------------/*** 解析唯一匹配给定对象类型(如果有的话)的bean实例,包括它的bean名称。* 比如我们调用getBean(User.class) 会匹配一个或多个bean,需要该方法进行选择* 这实际上是getBean(Class)的一个变体。*/<T> NamedBeanHolder<T> resolveNamedBean(Class<T> requiredType) throws BeansException;/*** 解析给定bean名称的bean实例, 向目标工厂方法公开提供依赖描述符。* 这实际上是getBean(String, Class)的一个变体,*/Object resolveBeanByName(String name, DependencyDescriptor descriptor) throws BeansException;/*** 针对此工厂中定义的bean解析指定的依赖项,注入的时候很有用。* 通过一个依赖的描述(对方法,字段,构造器的抽象),获得一个bean*/@NullableObject resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName) throws BeansException;}

BeanFactory 的 子接口:

  • 拓展了 自动注入 等相关能力
  • 它的能力被单独拎出来,因此允许非 Spring 组件的实例也借助它来实现自动装配;
  • 它的功能没有暴露给 ApplicationContext,但是在 ApplicationContext 上下文中,可以通过 ApplicationContext#getAutowireCapableBeanFactory 获取该实例,当然也可以直接获取 BeanFactory 进行类型转换。
  • 它定义了不同的粒度生命周期的相关方法,基于主要的几个里程碑比如 实例的创建 属性的填充 初始化回调 来划分,一般 Spring 内部自然是对 bean 实例执行全过程的生命周期。

ConfigurableBeanFactory

它是 HierarchicalBeanFactory 的子接口,在基础能力和分层能力之上拓展了配置能力,这是 Spring 常用的类设计模式,这一层抽象了所有 BeanFactory 类相关组件的维护,比如:

  • BeanExpressionResolverSpEL 解析器
  • ConversionService:转换服务
  • TypeConverter:类型转换的顶层接口,相当于整合了 ConversionServicePropertyEditorRegistry
  • BeanPostProcessor:支持添加 BeanPostProcessorbean实例 进行后处理
  • 等等
public interface ConfigurableBeanFactory extends HierarchicalBeanFactory, SingletonBeanRegistry {// 标准单例作用域的范围标识符:"singleton".自定义作用域可以通过 registerScope 添加String SCOPE_SINGLETON = "singleton";String SCOPE_PROTOTYPE = "prototype";// 设置此 bean 工厂的父级void setParentBeanFactory(BeanFactory parentBeanFactory) throws IllegalStateException;// 将 classLoader 设置为加载中的 bean 类,默认是线程上下文类装入器void setBeanClassLoader(@Nullable ClassLoader beanClassLoader);// 返回这个工厂的classLoader,用于加载bean类@NullableClassLoader getBeanClassLoader();/*** 指定一个临时ClassLoader用于类型匹配,默认为none。* 如果涉及到加载时织入,则通常只指定临时ClassLoader,以确保实际的bean类尽可能延迟地加载。* 一旦BeanFactory完成引导阶段,临时加载器就会被移除。*/void setTempClassLoader(@Nullable ClassLoader tempClassLoader);// 返回用于类型匹配的临时ClassLoader,ClassLoader getTempClassLoader();/**设置是否缓存bean元数据,例如给定的bean定义(以合并的方式)和 resolved bean classes关闭此标志可启动 bean Definition 和 特定bean类的热刷新如果该标志关闭,则任何bean实例的创建都将重新查询 bean class Loader 以获得新解析的类。**/void setCacheBeanMetadata(boolean cacheBeanMetadata);boolean isCacheBeanMetadata();// 设置和获取SpEL表达式解析器void setBeanExpressionResolver(@Nullable BeanExpressionResolver resolver);@NullableBeanExpressionResolver getBeanExpressionResolver();// 设置和获取转化服务void setConversionService(@Nullable ConversionService conversionService);@NullableConversionService getConversionService();// 添加属性编辑器void addPropertyEditorRegistrar(PropertyEditorRegistrar registrar);void registerCustomEditor(Class<?> requiredType, Class<? extends PropertyEditor> propertyEditorClass);void copyRegisteredEditorsTo(PropertyEditorRegistry registry);// 配置和获取类型转化器,相当于整合了 ConversationService 和 PropertyEditorRegistervoid setTypeConverter(TypeConverter typeConverter);TypeConverter getTypeConverter();// 为注入的值添加一个String解析器,如“aa${bb}cc”。void addEmbeddedValueResolver(StringValueResolver valueResolver);boolean hasEmbeddedValueResolver();String resolveEmbeddedValue(String value);// 添加和获取bean的后置处理器void addBeanPostProcessor(BeanPostProcessor beanPostProcessor);int getBeanPostProcessorCount();// 注册自定义的作用范围void registerScope(String scopeName, Scope scope);String[] getRegisteredScopeNames();@NullableScope getRegisteredScope(String scopeName);// 为这个bean工厂设置{ApplicationStartup} 用来记录启动步骤void setApplicationStartup(ApplicationStartup applicationStartup);ApplicationStartup getApplicationStartup();// 从一个bean工厂进行拷贝配置void copyConfigurationFrom(ConfigurableBeanFactory otherFactory);// 注册别名void registerAlias(String beanName, String alias) throws BeanDefinitionStoreException;// 获取合并的bean的定义(RootBeanDefinition)BeanDefinition getMergedBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;// 是否是工厂beanboolean isFactoryBean(String name) throws NoSuchBeanDefinitionException;// 控制指定bean当前的创建状态,仅供容器内部使用void setCurrentlyInCreation(String beanName, boolean inCreation);// 判断该bean是否在创建中boolean isCurrentlyInCreation(String beanName);// 为给定的bean注册一个依赖bean,在给定的bean被销毁之前销毁它void registerDependentBean(String beanName, String dependentBeanName);// 如果有的话,返回指定bean的所有bean的名称String[] getDependentBeans(String beanName);// 如果有的话,返回指定bean所依赖的所有bean的名称String[] getDependenciesForBean(String beanName);// 根据 bean 名称销毁给定的bean实例(通常是从该工厂获得的原型实例)void destroyBean(String beanName, Object beanInstance);// 销毁指定的【作用域bean】void destroyScopedBean(String beanName);// 销毁此工厂中的所有单例 Bean// 包括已注册一次性的内部bean。void destroySingletons();

ConfigurableListableBeanFactory

ConfigurableListableBeanFactory 把以上功能都整合在了一起,且拓展了核心方法 preInstantiateSingletons.

该方法用于在实例化 Bean 之前提前实例化单例Bean的,它首先迭代所有单例 Bean 的定义并检查是否是非延迟初始化的,并且如果是工厂 Bean,则还会检查是否需要提前初始化。然后,它会触发所有适用的Bean的后期初始化回调,并执行。

二、总结

  • BeanFactory:顶层接口,提供了最基础的方法,譬如:getBean、containBean
  • HierarchicalBeanFactory,子接口,拓展了 层次关系
  • ListableBeanFactory,子接口,拓展了 枚举 能力
  • AutowireCapableBeanFactory,子接口,拓展了 自动装配 能力
  • ConfigurableBeanFactory,子接口,拓展了相关组件 可配置化 的能力
  • ConfigurableListableBeanFactory,集大成者,直接实现类是 DefaultListableBeanFactory。

参考文献:

【源码】Spring —— BeanFactory 解读 1 BeanFactory 系列接口


http://www.ppmy.cn/news/1198101.html

相关文章

第四章IDEA操作Maven

文章目录 创建父工程开启自动导入配置Maven信息创建Java模块工程创建 Web 模块工程 在IDEA中执行Maven命令直接执行手动输入 在IDEA中查看某个模块的依赖信息工程导入来自版本控制系统来自工程目录 模块导入情景重现导入 Java 类型模块 导入 Web 类型模块 创建父工程 开启自动导…

Redis中的List类型

目录 List类型的命令 lpush lpushx rpush lrange lpop rpop lindex linsert llen lrem ltrim lset 阻塞命令 阻塞命令的使用场景 1.针对一个非空的列表进行操作 2.针对一个空的列表进行操作 3.针对多个key进行操作. 内部编码 lisi类型的应用场景 存储(班级…

【CIO人物展】黄淮学院副CIO周鹏:构建数智化平台赋能学校高质量发展

周鹏 本文由黄淮学院副CIO周鹏投递并参与《2023中国数智化转型升级优秀CIO》榜单/奖项评选。丨推荐企业—锐捷网络 大数据产业创新服务媒体 ——聚焦数据 改变商业 黄淮学院是2004年经教育部批准成立的一所省属全日制普通本科高校。学校位于素有“豫州之腹地、天下之最中”之美…

C# DateTime类型 直接使用Proto、Bson 问题

Proto问题 默认这里的时区为UTC、DateTimeOffset 为0&#xff0c;参考下面文档可找到&#xff1b;这就会导致设置的时区信息丢失,如下 eg. // json "VitalityUpdateTime":"2023-10-31T15:19:25.15050508:00", // proto, 没有带时区 "VitalityUpdateT…

多线程JUC 第2季 多线程的内存模型

一 内存模型 1.1 概述 在hotspot虚拟机里&#xff0c;对象在堆内存中的存储布局可以划分为3个部分&#xff1a;对象头&#xff1b;实例数据&#xff0c;对齐填充。如下所示&#xff1a;

逆向学习记录(2)windows常用基本操作及用环境变量配置上多个python版本

1、如何打开cmd 第一种方法&#xff1a;按下winr&#xff0c;运行cmd 第二种方法&#xff1a;进入一个目录&#xff0c;点击路径处&#xff08;显示蓝色背景&#xff09;&#xff0c;然后直接键盘输入cmd&#xff0c;回车&#xff0c;运行cmd并直接进入此目录。 2、命令dir&am…

基于单片机的智能拐杖软件设计

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 技术交流认准下方 CSDN 官方提供的联系方式 文章目录 概要 一、整体设计方案2.1本设计设计原理2.1.1单片机基本介绍 二、本设计方案选择三、软件设计AD原理图&#xff1a;原理图…

【开题报告】基于微信小程序的电子产品商城的设计与实现

1.研究背景 随着移动互联网的飞速发展&#xff0c;电子商务领域的竞争越来越激烈。作为中国最大的社交平台&#xff0c;微信拥有着庞大的用户群体和完善的生态系统&#xff0c;成为了电子商务领域的重要一员。 微信小程序作为微信的核心功能之一&#xff0c;具备“无需下载、…