【Spring源码分析】带你正视一下Spring祖容器之BeanFactory的原理与功能分析(1)
  TEZNKK3IfmPf 2023年11月12日 33 0

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 superior alternative to the Singleton design pattern, in which the instance is a singleton in the scope of the factory). Which type of instance will be returned depends on the bean factory configuration: the API is the same. Since Spring 2.0, further scopes are available depending on the concrete application context (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 registry of application components, and centralizes configuration of application components (no more do individual objects need to read properties files, for example). See chapters 4 and 11 of "Expert One-on-One J2EE Design and Development" 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 setters or constructors, rather than use any form of "pull" configuration like a BeanFactory lookup. Spring's Dependency Injection functionality is implemented using this BeanFactory interface and its subinterfaces.

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

Normally a BeanFactory will load bean definitions stored in a configuration source (such as an XML document), and use the {@code org.springframework.beans} package to configure the beans. However, an implementation could simply return Java objects it creates as necessary directly in Java code. There are no constraints on how the definitions could be stored: LDAP, RDBMS, XML, properties file, etc. Implementations are encouraged to support references amongst 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 the operations 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 instance are 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 interfaces as 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) throws NoSuchBeanDefinitionException;

  • 获取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 processor
Object 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);
【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月12日 0

暂无评论

推荐阅读
  TEZNKK3IfmPf   2024年05月17日   46   0   0 JSpspring