网站首页 > 技术文章 正文
Spring提供了两种容器类型:BeanFactory和ApplicationContext
BeanFactory
基础类型IoC容器,提供完整的IoC服务支持。如果没有特殊指定,默认采用延迟初始化策略(lazy-load)。只有当客户端对象需要访问容器中的某个受管对象的时候,才对 该受管对象进行初始化以及依赖注入操作。所以,相对来说,容器启动初期速度较快,所需 要的资源有限。对于资源有限,并且功能要求不是很严格的场景,BeanFactory是比较合适的 IoC容器选择。
ApplicationContext
ApplicationContext在BeanFactory的基础上构建,是相对比较高 级的容器实现,除了拥有BeanFactory的所有支持,ApplicationContext还提供了其他高级特性,比如事件发布、国际化信息支持等。ApplicationContext所管理 的对象,在该类型容器启动之后,默认全部初始化并绑定完成。所以,相对于BeanFactory来 说,ApplicationContext要求更多的系统资源,同时,因为在启动时就完成所有初始化,容 器启动时间较之BeanFactory也会长一些。在那些系统资源充足,并且要求更多功能的场景中,ApplicationContext类型的容器是比较合适的选择。
BeanFactory和Applicationontext的继承关系图:
BeanFactory接口中的方法
//主要包含以下方法(有许多重载方法)
Object getBean(String name) throws BeansException;
<T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);
boolean containsBean(String name);
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
上面代码中的方法基本上都是查询相关的方法,例如,取得某个对象的方法(getBean)、查询 某个对象是否存在于容器中的方法(containsBean),或者取得某个bean的状态或者类型的方法等 。
DefaultListableBeanFactory
BeanFactory只是一个接口,需要一个接口的实现类来进行Bean的管理。DefaultListableBeanFactory是BeanFactory接口的实现类。DefaultListableBeanFactory接口除了间接地实现了BeanFactory接口还实现了BeanDefinitionRegistry接口。
每一个受管的对象,在容器中都会有一个BeanDefinition的实例(instance)与之相对应,该BeanDefinition的实例负责保存对象的所有必要信息,包括其对应的对象的class类型、是否是抽象类、构造方法参数以及其他属性等。当客户端向BeanFactory请求相应对象的时候,BeanFactory会通过这些信息为客户端返回一个完备可用的对象实例。RootBeanDefinition和ChildBeanDefinition是BeanDefinition的两个主要实现类。
FactoryBean
某些对象的实例化过程过于烦琐,通过XML配置过于复杂,使我们宁愿使用Java代码来完成这 个实例化过程的时候,或者,某些第三方库(比如Mybatis)不能直接注册到Spring容器的时候,就可以实现org.spring.framework.beans.factory.FactoryBean接口,给出自己的对象实例化逻辑代代码。
FactoryBean作为一个接口,其内部仅包含三个方法:
T getObject() throws Exception;
Class<?> getObjectType();
default boolean isSingleton() {
return true;
}
getObjet()方法会返回按照程序员意愿使用FactoryBean生产出来的对象实例。 getObjectType()方法仅返回getObject()方法所返回的对象的类型,如果预先 无法确定,则返回null;isSingleton()方法返回结果用于表明,工厂方法(getObject())所“生 产”的对象是否要以singleton形式存在于容器中。如果以singleton形式存在,则返回true,否则返回false;
容器启动阶段
容器启动伊始,首先会通过某种途径加载Configuration MetaData。除了代码方式比较直接,在大部分情况下,容器需要依赖某些工具类(BeanDefinitionReader)对加载的Configuration MetaData 进行解析和分析,并将分析后的信息编组为相应的BeanDefinition,最后把这些保存了bean定义必 要信息的BeanDefinition,注册到相应的BeanDefinitionRegistry,这样容器启动工作就完成了。
干涉容器的启动
BeanFactoryPostProcess
Spring提供了一种叫做BeanFactoryPostProcessor的容器扩展机制。该机制允许我们在容器实 例化相应对象之前,对注册到容器的BeanDefinition所保存的信息做相应的修改。这就相当于在容 器实现的第一阶段最后加入一道工序,让我们对最终的BeanDefinition做一些额外的操作,比如修 改其中bean定义的某些属性,为bean定义增加其他信息等。
Bean的实例化阶段
经过第一阶段,现在所有的bean定义信息都通过BeanDefinition的方式注册到了BeanDefinitionRegistry中。当某个请求方通过容器的getBean方法明确地请求某个对象,或者因依赖关系容器 需要隐式地调用getBean方法时,就会触发第二阶段的活动。
该阶段,容器会首先检查所请求的对象之前是否已经初始化。如果没有,则会根据注册的 BeanDefinition所提供的信息实例化被请求对象,并为其注入依赖。如果该对象实现了某些回调接口,也会根据回调接口的要求来装配它。当该对象装配完毕之后,容器会立即将其返回请求方使用。
容器启动之后,并不会马上就实例化相应的bean定义。我们知道,容器现在仅仅拥有所有对象的 BeanDefinition来保存实例化阶段将要用的必要信息。只有当请求方通过BeanFactory的getBean() 方法来请求某个对象实例的时候,才有可能触发Bean实例化阶段的活动。BeanFactory的getBe 法可以被客户端对象显式调用,也可以在容器内部隐式地被调用。隐式调用有如下两种情况。
对于BeanFactory来说,对象实例化默认采用延迟初始化。通常情况下,当对象A被请求而需 要第一次实例化的时候,如果它所依赖的对象B之前同样没有被实例化,那么容器会先实例化 对象A所依赖的对象。这时容器内部就会首先实例化对象B,以及对象 A依赖的其他还没有 实例化的对象。这种情况是容器内部调用getBean(),对于本次请求的请求方是隐式的。
ApplicationContext
较之BeanFactory更为先进的IoC容器实现,ApplicationContext除了拥有 BeanFactory支持的所有功能之外,还进一步扩展了基本容器的功能,包括BeanFactoryPostProcessor、BeanPostProcessor以及其他特殊类型bean的自动识别、容器启动后bean实例的自动初始化、 国际化的信息支持、容器内事件发布等。
猜你喜欢
- 2025-01-12 抽象基类,一个非常实用但容易被忽视的宝藏Python知识点
- 2025-01-12 Java 中使用抽象类实现接口的作用及方法解析
- 2025-01-12 复习java接口和抽象类的作用与区别
- 2025-01-12 接口和抽象类的区别
- 2025-01-12 自定义类加载器实现及在tomcat中的应用
- 2025-01-12 抽象函数的8类常考题型
- 2025-01-12 面试官:总结一下接口与抽象类的区别,聊聊关于类的名词
- 2025-01-12 Java的抽象类与举例说明
- 2025-01-12 抽象类和接口的区别
- 2025-01-12 深刻理解 接口vs抽象类的区别?
- 02-21走进git时代, 你该怎么玩?_gits
- 02-21GitHub是什么?它可不仅仅是云中的Git版本控制器
- 02-21Git常用操作总结_git基本用法
- 02-21为什么互联网巨头使用Git而放弃SVN?(含核心命令与原理)
- 02-21Git 高级用法,喜欢就拿去用_git基本用法
- 02-21Git常用命令和Git团队使用规范指南
- 02-21总结几个常用的Git命令的使用方法
- 02-21Git工作原理和常用指令_git原理详解
- 最近发表
- 标签列表
-
- cmd/c (57)
- c++中::是什么意思 (57)
- sqlset (59)
- ps可以打开pdf格式吗 (58)
- phprequire_once (61)
- localstorage.removeitem (74)
- routermode (59)
- vector线程安全吗 (70)
- & (66)
- java (73)
- org.redisson (64)
- log.warn (60)
- cannotinstantiatethetype (62)
- js数组插入 (83)
- resttemplateokhttp (59)
- gormwherein (64)
- linux删除一个文件夹 (65)
- mac安装java (72)
- reader.onload (61)
- outofmemoryerror是什么意思 (64)
- flask文件上传 (63)
- eacces (67)
- 查看mysql是否启动 (70)
- java是值传递还是引用传递 (58)
- 无效的列索引 (74)