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

Posted 李浩宇Alex

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring源码分析带你正视一下Spring祖容器之BeanFactory的原理与功能分析相关的知识,希望对你有一定的参考价值。

BeanFactory

BeanFactory类的介绍

BeanFactory里注释进行详细分析.

BeanFactory的介绍说明

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

BeanFactory的作用范围

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

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

BeanFactory的作用职能

  • 这种方案的关键是,BeanFactory的是应用程序组件注册的中心,同时集中应用程序组件的配置(程序模块不再需要读取诸如properties的配置文件)。这种设计的更多好处讨论详见的<J2EE设计开发编程指南>第4和第11章.
  • 相比诸如 BeanFactory 中查找的pull配置方式,通过setters或者构造方法,依赖注入的方式配置应用对象更好,Spring的依赖注入功能就是通过实现BeanFactory和其子接口实现的.
  • 通常,一个BeanFactory会从配置源(如XML文件)中加载bean对象模型,并使用{@code org.springframework.beans}包解析bean。然而,实现可以简单地返回Java代码直接新建的Java对象。这里没有限制bean 定义文件的格式:LDAP,RDBMS,XML.实现类欢迎支持应用而非bean(依赖注入)
  • 对比{@ListableBeanFactory}中的方法,如果这是一个{@link HierarchicalBeanFactory},这个接口的全部实现都会查找父工厂,如果在这个工厂实例找不到bean,去直接父工厂查找。factory实例中的bean会覆盖父factory实例中的同名bean。
  • 实现类应该尽量支持标准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);
}
  • 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的架构模型机制

  • 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

获取父容器 bean factory
判断当前容器是否保护bean

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定义,所以应用不需要顾虑这些差别.

暴力获取全部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);

以上是关于Spring源码分析带你正视一下Spring祖容器之BeanFactory的原理与功能分析的主要内容,如果未能解决你的问题,请参考以下文章

深入浅出Spring原理及实战「原理分析专题」不看源码就带你剖析IOC容器核心流程以及运作原理

Spring 专场「IOC 容器」不看源码就带你认识核心流程以及运作原理

「Spring 」「AOP 容器」不看源码就带你认识核心流程以及运作原理

深入浅出Spring原理及实战「原理分析专题」不看源码就带你剖析MVC容器核心流程以及运作原理

Spring专场「MVC容器」不看源码就带你认识核心流程以及运作原理

spring依赖注入源码分析