写点什么

【Spring 源码分析】带你正视一下 Spring 祖容器之 BeanFactory 的原理与功能分析(1)

发布于: 刚刚
【Spring源码分析】带你正视一下Spring祖容器之BeanFactory的原理与功能分析(1)

BeanFactory

BeanFactory 是 Spring bean 容器的根接口,BeanFactory 作为应用集中配置管理的地方,极大简便应用开发,这样开发人员可以集中与业务,这边定义了一系列的接口,通过这些接口的学习,可以大致了解 BeanFactory 体系各接口如何分工合作.

BeanFactory 类的介绍

BeanFactory 是 Spring 实现依赖注入的核心接口,提供应用的统一配置注册功能,实现业务开发解偶。使用 getBean 可以代替单例,原型设计模式.


BeanFactory 里注释进行详细分析.

BeanFactory 的介绍说明

The root interface for accessing a Spring bean container.This is the basic client view of a bean container;further interfaces such as {@link ListableBeanFactory} and{@link org.springframework.beans.factory.config.ConfigurableBeanFactory}are available for specific purposes


  • 访问一个 Spring bean 容器的根接口。这是一个 bean 容器的基本客户端视图;进一步的接口,如 ListableBeanFactory 和 org.springframework.beans.factory.config.ConfigurableBeanFactory}可用于特殊目的。

BeanFactory 的作用范围

This interface is implemented by objects that hold a number of bean definitions,each uniquely identified by a String name. Depending on the bean definition,the factory will return either an independent instance of a contained object(the Prototype design pattern), or a single shared instance (a superioralternative to the Singleton design pattern, in which the instance is asingleton in the scope of the factory).Which type of instance will be returneddepends on the bean factory configuration: the API is the same. Since Spring2.0, further scopes are available depending on the concrete applicationcontext (e.g. "request" and "session" scopes in a web environment).


  • 此接口由持有一些 bean 定义的对象来实现,每个 bean 由 String 字符串唯一标识。根据 bean 定义,工厂将返回一个独立对象实例(原型设计模式),或者一个单个共享实例(Singleton 设计模式的优雅代替实现,其中该实例是一个 factory 范围内的单例)。

  • 实例的哪种类型将被返回依赖于 bean 工厂配置:即使 API 是一样的。从 Spring2.0 开始,作用域扩展到根据具体的应用上下文,如 web 环境的 request,session。

BeanFactory 的作用职能

The point of this approach is that the BeanFactory is a central registryof application components, and centralizes configuration of applicationcomponents (no more do individual objects need to read properties files,for example). See chapters 4 and 11 of "Expert One-on-One J2EE Design andDevelopment" for a discussion of the benefits of this approach.


  • 这种方案的关键是,BeanFactory 的是应用程序组件注册的中心,同时集中应用程序组件的配置(程序模块不再需要读取诸如 properties 的配置文件)。这种设计的更多好处讨论详见的<J2EE 设计开发编程指南>第 4 和第 11 章.


Note that it is generally better to rely on Dependency Injection("push" configuration) to configure application objects through settersor constructors, rather than use any form of "pull" configuration like aBeanFactory lookup. Spring's Dependency Injection functionality isimplemented using this BeanFactory interface and its subinterfaces.


  • 相比诸如 BeanFactory 中查找的 pull 配置方式,通过 setters 或者构造方法,依赖注入的方式配置应用对象更好,Spring 的依赖注入功能就是通过实现 BeanFactory 和其子接口实现的.


Normally a BeanFactory will load bean definitions stored in a configurationsource (such as an XML document), and use the {@code org.springframework.beans}package to configure the beans. However, an implementation could simply returnJava objects it creates as necessary directly in Java code. There are noconstraints on how the definitions could be stored: LDAP, RDBMS, XML,properties file, etc. Implementations are encouraged to support referencesamongst beans (Dependency Injection).


  • 通常,一个 BeanFactory 会从配置源(如 XML 文件)中加载 bean 对象模型,并使用{@code org.springframework.beans}包解析 bean。然而,实现可以简单地返回 Java 代码直接新建的 Java 对象。这里没有限制 bean 定义文件的格式:LDAP,RDBMS,XML.实现类欢迎支持应用而非 bean(依赖注入)


In contrast to the methods in {@link ListableBeanFactory}, all of theoperations in this interface will also check parent factories if this is a{@link HierarchicalBeanFactory}. If a bean is not found in this factory instance,the immediate parent factory will be asked. Beans in this factory instanceare supposed to override beans of the same name in any parent factory.


  • 对比{@ListableBeanFactory}中的方法,如果这是一个{@link HierarchicalBeanFactory},这个接口的全部实现都会查找父工厂,如果在这个工厂实例找不到 bean,去直接父工厂查找。factory 实例中的 bean 会覆盖父 factory 实例中的同名 bean。


Bean factory implementations should support the standard bean lifecycle interfacesas far as possible.


  • 实现类应该尽量支持标准 bean 的生命周期接口.全套的初始化方法。


public interface BeanFactory {
/** * 用于区分是否直接获取FactoryBean实例. * bean以&开头表示获取FactoryBean实例.否则获取created的实例.For example, if the bean named * {@code myJndiObject} is a FactoryBean, getting {@code &myJndiObject} * will return the factory, not the instance returned by the factory. */ String FACTORY_BEAN_PREFIX = "&";
/** * 返回一个原型或者单例实例. * 抢单例,原型设计模式的饭碗 * 可以根据别名查找,也可以去父容器实例查找 */ Object getBean(String name) throws BeansException;
/** * 加个类型 */ <T> T getBean(String name, Class<T> requiredType) throws BeansException;
/** * 根据类型获取bean实例.可以是接口或子类,但不能是{@code null}. * {@link ListableBeanFactory}也可以使用类型转化为name进行查找.更多bean集合的操作可以看 * ListableBeanFactory和BeanFactoryUtils */ <T> T getBean(Class<T> requiredType) throws BeansException;
/** * 多了构造方法,工厂方法的参数 */ Object getBean(String name, Object... args) throws BeansException;
/** * 判断是否包含bean(包括别名,父容器) * 陷阱出现:这边不管类是否抽象类,懒加载,是否在容器范围内,只要符合都返回true,所以这边true,不一定能从getBean获取实例 */ boolean containsBean(String name);
/** * 是否单例 */ boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
/** * 是否原型 */ boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
/** * 是否有跟name匹配类型的bean */ boolean isTypeMatch(String name, Class<?> targetType) throws NoSuchBeanDefinitionException;
/** * 根据bean name获取类型 */ Class<?> getType(String name) throws NoSuchBeanDefinitionException;
/** * 获取别名 */ String[] getAliases(String name);}
复制代码


接口里定义了一个变量 String FACTORY_BEAN_PREFIX = "&": 用来区分是获取 FactoryBean 还是 FactoryBean 的 createBean 创建的实例,如果 &开始则获取 FactoryBean;否则获取 createBean 创建的实例.


  • Object getBean(String name) throws BeansException; 可以用别名查找哦

  • <T> T getBean(String name, Class<T> requiredType) throws BeansException;

  • <T> T getBean(Class<T> requiredType) throws BeansException; 这边的类型可以是接口或者子类,但不能是 null

  • Object getBean(String name, Object... args) throws BeansException;

  • 判断是否包含 bean.陷阱出现:这边不管类是否抽象类,懒加载,是否在容器范围内,只要符合都返回 true,所以这边 true,不一定能从 getBean 获取实例

  • boolean containsBean(String name);

  • 单例,原型,bean 类型的判断

  • boolean isSingleton(String name) throws NoSuchBeanDefinitionException;


- boolean isPrototype(String name) throws NoSuchBeanDefinitionException;


- boolean isTypeMatch(String name, Class<?> targetType) throwsNoSuchBeanDefinitionException;


  • 获取 bean 的类型,别名

  • Class<?> getType(String name) throws NoSuchBeanDefinitionException;

  • String[] getAliases(String name);

BeanFactory 的架构模型机制

BeanFactory 是 Spring bean 容器的根接口,提供获取 bean,是否包含 bean,是否单例与原型,获取 bean 类型,bean 别名的 api。


  • AutowireCapableBeanFactory 添加集成其他框架功能,如果集成 WebWork 则可以使用 Spring 对 Actions 等进行管理.

  • HierarchicalBeanFactory:提供父容器的访问功能

  • ConfigurableBeanFactory:如名,提供 factory 的配置功能。

  • ConfigurableListableBeanFactory:集大成者,提供解析,修改 bean 定义,并与初始化单例.

  • ListableBeanFactory 提供容器内 bean 实例的枚举功能,这边不会考虑父容器内的实例.


AutowireCapableBeanFactory

在 BeanFactory 基础上实现对已存在实例的管理.


  • 可以使用这个接口集成其它框架,捆绑并填充并不由 Spring 管理生命周期并已存在的实例.像集成其他框架机制。

  • 一般应用开发者不会使用这个接口,所以像 ApplicationContext 这样的外观实现类不会实现这个接口,如果真手痒痒可以通过 ApplicationContext 的 getAutowireCapableBeanFactory 接口获取。


这边定义了 5 种自动装配策略:


  • 不注入:AUTOWIRE_NO

  • 使用 bean name 策略装配:AUTOWIRE_BY_NAME

  • 使用类型装配策略:AUTOWIRE_BY_TYPE

  • 使用构造器装配策略:AUTOWIRE_CONSTRUCTOR

  • 自动装配策略:AUTOWIRE_AUTODETECT


这边的自动策略是先尝试构造器,然后才是 byType,应该是跟 xml 配置文件中的装配策略对应。

创建和填充外部 bean 实例的典型方法

<T> T createBean(Class<T> beanClass) throws BeansException;
// 使用autowireBeanProperties装配属性void autowireBean(Object existingBean) throws BeansException;
// 自动装配属性,填充属性值,使用诸如setBeanName,setBeanFactory这样的工厂回调填充属性,最好还要调用post processorObject configureBean(Object existingBean, String beanName) throws BeansException;
Object resolveDependency(DependencyDescriptor descriptor, String beanName) throws BeansException;
复制代码

在 bean 的生命周期进行细粒度控制的专门方法

Object createBean(Class<?> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException; // 会执行bean完整的初始化,包括BeanPostProcessors和initializeBean
Object autowire(Class<?> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException;
void autowireBeanProperties(Object existingBean, int autowireMode, boolean dependencyCheck) throws BeansException;
void applyBeanPropertyValues(Object existingBean, String beanName) throws BeansException;
Object initializeBean(Object existingBean, String beanName) throws BeansException;
Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException;
Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException;
Object resolveDependency(DependencyDescriptor descriptor, String beanName, Set<String> autowiredBeanNames, TypeConverter typeConverter) throws BeansException;
复制代码

HierarchicalBeanFactory

提供父容器的访问功能.至于父容器的设置,需要找 ConfigurableBeanFactory 的 setParentBeanFactory(接口把设置跟获取给拆开了!).

获取父容器 bean factory

BeanFactory getParentBeanFactory();

判断当前容器是否保护 bean

boolean containsLocalBean(String name);

ListableBeanFactory

获取 bean 时,Spring 鼓励使用这个接口定义的 api,其他的 4 个接口都是不鼓励使用的.


提供容器中 bean 迭代的功能,不再需要一个个 bean 地查找,比如可以一次获取全部的 bean,根据类型获取 bean.在看 SpringMVC 时,扫描包路径下的具体实现策略就是使用的这种方式(那边使用的是 BeanFactoryUtils 封装的 api).


如果同时实现了 HierarchicalBeanFactory,返回值不会考虑父类 BeanFactory,只考虑当前 factory 定义的类.当然也可以使用 BeanFactoryUtils 辅助类来查找祖先工厂中的类.


  • 这个接口中的方法只会考虑本 factory 定义的 bean.

  • 这些方法会忽略 ConfigurableBeanFactory 的 registerSingleton 注册的单例 bean(getBeanNamesOfType 和 getBeansOfType 是例外,一样会考虑手动注册的单例).

  • 当然 BeanFactory 的 getBean 一样可以透明访问这些特殊 bean.当然在典型情况下,所有的 bean 都是由 external bean 定义,所以应用不需要顾虑这些差别.


注意:getBeanDefinitionCount 和 containsBeanDefinition 的实现方法因为效率比较低,还是少用为好.


暴力获取全部 bean 的属性:


  • boolean containsBeanDefinition(String beanName); //是否包含 bean

  • int getBeanDefinitionCount(); // 当前 factory 中定义的 bean 数量

  • String[] getBeanDefinitionNames(); // 获取当前工厂中定义的所有 bean 的 name


根据 bean 的类型获取 bean


这边的方法仅检查顶级 bean.它不会检查嵌套的 bean.FactoryBean 创建的 bean 会匹配为 FactoryBean 而不是原始类型.


一样不会考虑父 factory 中的 bean,非要用可以通过 BeanFactoryUtils 中的 beanNamesForTypeIncludingAncestors.


这个版本的 getBeanNamesForType 会匹配所有类型的 bean,包括单例,原型,FactoryBean.返回的 bean names 会根据 backend 配置的进行排序.


  • String[] getBeanNamesForType(Class<?> type); // 获取给定类型的 bean names(包括子类),通过 bean 定义或者 FactoryBean 的 getObjectType 判断.

  • String[] getBeanNamesForType(Class<?> type, boolean includeNonSingletons, boolean allowEagerInit);

  • <T> Map<String, T> getBeansOfType(Class<T> type) throws BeansException; // 如果保护懒加载的类,FactoryBean 初始化的类和工厂方法初始化的类会被初始化.就是说执行这个方法会执行对应的初始化.

  • <T> Map<String, T> getBeansOfType(Class<T> type, boolean includeNonSingletons, boolean allowEagerInit) throws BeansException;


查找使用注解的类


  • Map<String, Object> getBeansWithAnnotation(Class<? extends Annotation> annotationType) throws BeansException;


查找一个类上的注解,如果找不到,父类,接口使用注解也算.


  • <A extends Annotation> A findAnnotationOnBean(String beanName, Class<A> annotationType);

发布于: 刚刚阅读数: 2
用户头像

🏆 2021年InfoQ写作平台-签约作者 🏆 2020.03.25 加入

👑【酷爱计算机技术、醉心开发编程、喜爱健身运动、热衷悬疑推理的”极客狂人“】 🏅 【Java技术领域,MySQL技术领域,APM全链路追踪技术及微服务、分布式方向的技术体系等】 “任何足够先进的技术都是魔法“

评论

发布
暂无评论
【Spring源码分析】带你正视一下Spring祖容器之BeanFactory的原理与功能分析(1)