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容器核心流程以及运作原理