第十一篇

博客园Logo
首页
新闻
博问
专区
闪存
云上钜惠
代码改变世界
搜索
注册
登录
返回主页
锅外的大佬
每日推送国外优秀的技术翻译文章,励志帮助国内的开发者更好地成长!
博客园
首页
新随笔
联系
订阅
管理
为什么大多数IOC容器使用ApplicationContext,而不用BeanFactory

  1. 引言
    Spring框架附带了两个IOC容器– BeanFactory 和 ApplicationContext. BeanFactory是IOC容器的最基本版本,ApplicationContext扩展了BeanFactory的功能。
    那么本篇文章中,我们将通过实际例子了解这两个IOC容器之间的显著差异。

  2. 延迟加载 vs. 预加载
    BeanFactory 按需加载bean,而 ApplicationContext 则在启动时加载所有bean。因此,BeanFactory与ApplicationContext相比是轻量级的。让我们用一个例子来理解它。

2.1. BeanFactory 延迟加载
假设我们有一个名为 Student 单例Bean:

public class Student {
public static boolean isBeanInstantiated = false;

public void postConstruct() {
    setBeanInstantiated(true);
}

//standard setters and getters

}
我们将把 postConstruct() 方法定义为BeanFactory配置文件 ioc-container-difference-example.xml 中的 init method:

现在,让我们编写一个测试用例来创建一个BeanFactory 来检查它是否加载了Student bean:

@Test
public void whenBFInitialized_thenStudentNotInitialized() {
Resource res = new ClassPathResource(“ioc-container-difference-example.xml”);
BeanFactory factory = new XmlBeanFactory(res);

assertFalse(Student.isBeanInstantiated());

}
这里,没有初始化 Student 对象。换句话说,只有 BeanFactory 被初始化了。只有当我们显式调用getBean()方法时,BeanFactory 中定义的 bean 才会被加载。
让我们检查一下 Student bean 的初始化情况,我们手动调用 getBean() 方法:

@Test
public void whenBFInitialized_thenStudentInitialized() {
Resource res = new ClassPathResource(“ioc-container-difference-example.xml”);
BeanFactory factory = new XmlBeanFactory(res);
Student student = (Student) factory.getBean(“student”);

assertTrue(Student.isBeanInstantiated());

}
这里,Student bean 成功加载。因此,BeanFactory 只在需要时加载bean。

2.2. ApplicationContext 预加载
现在,让我们用ApplicationContext代替BeanFactory
我们只定义ApplicationContext,它将使用预加载策略立即加载所有bean:

@Test
public void whenAppContInitialized_thenStudentInitialized() {
ApplicationContext context = new ClassPathXmlApplicationContext(“ioc-container-difference-example.xml”);

assertTrue(Student.isBeanInstantiated());

}
在这里,即使我们没有调用 getBean() 方法,也会创建 Student 对象
ApplicationContext 被认为是一个沉重的IOC容器,因为它的预加载策略在启动时加载所有bean。相比之下,BeanFactory 是轻量级的,在内存受限的系统中非常方便。尽管如此,大多数用例仍然首选使用 ApplicationContext,这是为什么呢?

  1. 企业应用程序功能
    ApplicationContext 以更面向框架的风格增强了BeanFactory,并提供了一些适用于企业应用程序的功能。

例如,它提供了消息传递(i18n或国际化)功能、事件发布功能、基于注释的依赖注入,以及与Spring AOP特性的简单集成。

除此之外,ApplicationContext几乎支持所有类型的 bean 作用域,但是BeanFactory只支持两个作用域——Singleton和Prototype。因此,在构建复杂的企业应用程序时,最好使用ApplicationContext。

  1. 自动注册BeanFactoryPostProcessor和BeanPostProcessor
    **ApplicationContext 在启动时自动注册 BeanFactoryPostProcessor 和 BeanPostProcessor **。然而,BeanFactory不会自动注册这些接口。

4.1. 在 BeanFactory 中注册
为了理解,让我们写两个类。
首先,我们有CustomBeanFactoryPostProcessor类,它实现了BeanFactoryPostProcessor:

public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
private static boolean isBeanFactoryPostProcessorRegistered = false;

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory){
    setBeanFactoryPostProcessorRegistered(true);
}

// standard setters and getters

}
这里,我们重写了 postProcessBeanFactory() 方法来检查它的注册。
其次,我们还有另一个类,CustomBeanPostProcessor,它实现了BeanPostProcessor:

public class CustomBeanPostProcessor implements BeanPostProcessor {
private static boolean isBeanPostProcessorRegistered = false;

@Override
public Object postProcessBeforeInitialization(Object bean, String beanName){
    setBeanPostProcessorRegistered(true);
    return bean;
}

//standard setters and getters

}
这里,我们重写了 PostProcessBeforeAlization() 方法来检查其注册。
另外,我们在 ioc-container-difference-example.xml 配置文件中配置了这两个类:



让我们看一个测试用例来检查这两个类是否在启动期间自动注册:

@Test
public void whenBFInitialized_thenBFPProcessorAndBPProcessorNotRegAutomatically() {
Resource res = new ClassPathResource(“ioc-container-difference-example.xml”);
ConfigurableListableBeanFactory factory = new XmlBeanFactory(res);

assertFalse(CustomBeanFactoryPostProcessor.isBeanFactoryPostProcessorRegistered());
assertFalse(CustomBeanPostProcessor.isBeanPostProcessorRegistered());

}
从我们的测试中我们可以看到,自动注册并没有发生。
现在,让我们看看一个测试用例,手动将它们添加到 BeanFactory:

@Test
public void whenBFPostProcessorAndBPProcessorRegisteredManually_thenReturnTrue() {
Resource res = new ClassPathResource(“ioc-container-difference-example.xml”);
ConfigurableListableBeanFactory factory = new XmlBeanFactory(res);

CustomBeanFactoryPostProcessor beanFactoryPostProcessor 
  = new CustomBeanFactoryPostProcessor();
beanFactoryPostProcessor.postProcessBeanFactory(factory);
assertTrue(CustomBeanFactoryPostProcessor.isBeanFactoryPostProcessorRegistered());

CustomBeanPostProcessor beanPostProcessor = new CustomBeanPostProcessor();
factory.addBeanPostProcessor(beanPostProcessor);
Student student = (Student) factory.getBean("student");
assertTrue(CustomBeanPostProcessor.isBeanPostProcessorRegistered());

}
这里,我们使用 postProcessBeanFactory() 方法注册 CustomBeanFactoryPostProcessor,使用 addBeanPostProcessor() 方法注册CustomBeanPostProcessor。在这种情况下,它们都注册成功。

4.2. 在 ApplicationContext 中注册
如前所述,ApplicationContext会自动注册这两个类,而无需编写额外的代码。
让我们在单元测试中验证此行为:

@Test
public void whenAppContInitialized_thenBFPostProcessorAndBPostProcessorRegisteredAutomatically() {
ApplicationContext context
= new ClassPathXmlApplicationContext(“ioc-container-difference-example.xml”);

assertTrue(CustomBeanFactoryPostProcessor.isBeanFactoryPostProcessorRegistered());
assertTrue(CustomBeanPostProcessor.isBeanPostProcessorRegistered());

}
我们可以看到,这两个类的自动注册都是成功的。
因此,建议使用ApplicationContext,因为Spring2.0(及更高版本)大量使用BeanPostProcessor。
还有一点值得注意的是如果使用的是普通的 BeanFactory,那么事务和AOP之类的功能将不会生效(除非你编写额外的代码实现,那就另当别论了)。这样可能会导致代码很混乱,因为配置看起来貌似没毛病。

  1. 写在结尾
    ApplicationContext 提供了一些高级功能,包括一些面向企业应用程序的功能,而BeanFactory只提供了基本功能。因此,一般建议使用 ApplicationContext ,只有在内存消耗非常关键的情况下,我们才应该考虑去使用BeanFactory。
    如果你觉得文章还不错,记得关注公众号: 锅外的大佬
    刘一手的博客

好文要顶 关注我 收藏该文
锅外的大佬
关注 - 1
粉丝 - 26
+加关注
00
« 上一篇: 重温Java泛型,带你更深入地理解它,更好的使用它!
posted @ 2020-11-13 08:43 锅外的大佬 阅读(20) 评论(0) 编辑 收藏
刷新评论刷新页面返回顶部
登录后才能发表评论,立即 登录 或 注册, 访问 网站首页
博客园派送云上免费午餐,AWS注册立享12个月免费套餐
【推荐】News: 大型组态、工控、仿真、CADGIS 50万行VC++源码免费下载
【推荐】博客园 & 陌上花开HIMMR 给单身的程序员小哥哥助力脱单啦~
【推荐】博客园 & 示说网联合策划,AI实战系列公开课第二期
【推荐】了不起的开发者,挡不住的华为,园子里的品牌专区
【推荐】未知数的距离,毫秒间的传递,声网与你实时互动
【福利】AWS携手博客园为开发者送免费套餐与抵扣券
【推荐】 阿里云折扣价格返场,错过再等一年

声网专区
最新 IT 新闻:
· 拼多多财报电话会议实录:多多买菜并非社区拼团购物
· 久经沙场的战士对决:张小龙大战张一鸣
· 双十一吐槽:异化与集体无意识
· 小鹏汽车上市后首份财报:营收19亿 首度实现毛利转正
· 腾讯第三季度总收入为1254.47亿元 同比增长29%
» 更多新闻…
历史上的今天:
2019-11-13 用Java实现简单的区块链
公告
关注公众号
→「干货译文」提升软硬实力
→「技术趋势」感受优秀思想
→「工具汇总」高效高质工作

  • 专注翻译国外最新技术文章
  • 愿帮助国内开发者砥砺前行

2019年7月最新Java微服务资料
昵称: 锅外的大佬
园龄: 1年5个月
粉丝: 26
关注: 1
+加关注
< 2020年11月 >
日 一 二 三 四 五 六
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 1 2 3 4 5
6 7 8 9 10 11 12
搜索

我的标签
spring boot(34)
springmvc(32)
微服务(32)
java(32)
microservice(32)
spring(32)
DTO(1)
Entity(1)
Spring Cloud(1)
Spring Data JPA(1)
随笔档案 (76)
2020年11月(5)
2020年8月(1)
2020年7月(1)
2020年5月(1)
2020年4月(2)
2020年3月(1)
2019年12月(1)
2019年11月(4)
2019年10月(3)
2019年9月(12)
2019年8月(6)
2019年7月(13)
2019年6月(17)
2019年5月(9)
最新评论

  1. Re:重温Java泛型,带你更深入地理解它,更好的使用它!
    写的蛮清楚的,点赞

–张小泽的小号
2. Re:Spring Cloud Turbine
博主, 咨询个问题, 我通过eureka 获取服务名称, 把所以的服务都注册到 Turbine 中 同时也按照服务名称设置集群了。 有个问题是,Turbine 启动后就会拉取 配置的微服务数据, 注册…
–atliwen
3. Re:Spring Boot中使用RSocket
MarketDataRepository 这个是什么啊

–小男孩的Code
4. Re:对比Memcached和Redis,谁才是适合你的缓存?
redis比较快吧 尤其在小文件的场景下

–哈啾小包子
5. Re:最好的重试是指数后退和抖动
感谢分享
–匠心十年
阅读排行榜

  1. 如何排查Java内存泄漏?看完我给跪了!(22127)
  2. Spring Batch 入门级示例教程(16752)
  3. Java中创建对象的5种方法(7191)
  4. Spring Boot中使用RSocket(6302)
  5. Spring Boot: Spring Doc生成OpenAPI3.0文档(6116)
    评论排行榜
  6. Java动态规划(3)
  7. 如何成为更好的程序员?(2)
  8. 如何排查Java内存泄漏?看完我给跪了!(2)
  9. 重温Java泛型,带你更深入地理解它,更好的使用它!(1)
  10. 对比Memcached和Redis,谁才是适合你的缓存?(1)
    推荐排行榜
  11. 如何有效的读一本书?各位读书人,确定自己真的会读书吗?(4)
  12. 最好的重试是指数后退和抖动(3)
  13. Java中的关键字synchronized(3)
  14. 重温Java泛型,带你更深入地理解它,更好的使用它!(2)
  15. 不管你年底换不换工作,了解下单例模式(2)
    Copyright © 2020 锅外的大佬
    Powered by .NET 5.0.0 on Kubernetes
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值