IoC容器16——BeanFactory

原创
2017/07/26 16:27
阅读数 40

BeanFactory为Spring的IoC功能提供底层的基础,但是它只直接用于与其它第三发框架集成,并且对于使用它的大部分Spring用户来说都是历史原因造成的。BeanFactory和相关接口,例如BeanFactoryAware、InitializingBean、DisposableBean,仍然在Spring被提供,为了向后兼容与Spring集成的大量第三发框架。很多时候第三方组件不能使用更现代的方式例如@PostConstruct或@PreDestory,一般是为了保持对JDK 1.4的兼容或去除对JSR-250的依赖。

本节提供了额外的背景关于BeanFactory与ApplicationContext之间的不同之处和如何通过典型的单例查找来直接获取IoC容器。

1 BeanFactory 还是 ApplicationContext

应使用ApplicationContext除非有一个好的理由不这么做。

因为ApplicationContext包含了BeanFactory的所有功能,通常推荐不使用BeanFactory,除了几种情况,例如在资源有限的设备上运行的嵌入式应用程序,其内存消耗可能至关重要并且额外的千字节可能会有很大的不同。对于大多数典型的企业级应用和系统,ApplicationContext是首选。Spring大量使用了BeanPostProcessor扩展点(以实现代理等等)。如果仅仅想使用普通的BeanFactory,大量的支持例如事务和AOP都不会生效,至少在不进行任何额外操作时不会生效。这种情况可能让人迷惑,因为事实上配置并没有发生错误。

下面的表格列出了BeanFactory和ApplicationContext接口和实现提供的功能。

功能 BeanFactory ApplicationContext
Bean实例化和装配 Yes Yes
自动注册BeanPostProcessor No Yes
自动注册BeanFactoryPostProcessor No Yes
方便的获取MessageSource(国际化使用) No Yes
ApplicationEvent发布 No Yes

使用BeanFactory实现需要明确的注册bean后处理器,像下面一样编写代码:

DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
// populate the factory with bean definitions

// now register any needed BeanPostProcessor instances
MyBeanPostProcessor postProcessor = new MyBeanPostProcessor();
factory.addBeanPostProcessor(postProcessor);

// now start using the factory

使用BeanFactory实现需要明确的注册BeanFactoryPostProcessor,像下面一样编写代码:

DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
reader.loadBeanDefinitions(new FileSystemResource("beans.xml"));

// bring in some property values from a Properties file
PropertyPlaceholderConfigurer cfg = new PropertyPlaceholderConfigurer();
cfg.setLocation(new FileSystemResource("jdbc.properties"));

// now actually do the replacement
cfg.postProcessBeanFactory(factory);

在这两个例子中,明确的注册步骤是繁琐的,这是其中一个在绝大多数Spring支持的应用程序中推荐各种ApplicationContext实现而不是普通BeanFactory实现的原因,特别是当使用BeanFactoryPostProcessor和BeanPostProcessor时。这些ApplicationContext实现了重要的功能例如属性占位符替换和AOP。

2 粘合代码和坏单例

最好使用依赖注入风格编写绝大部分应用代码,这些代码在Spring IoC容器之外,当被创建时由容器提供依赖关系,并且它们完全不知道容器的存在。然而对于少量的粘合层代码(???原文 for the small glue layers code),有时需要与其它代码绑定在一起,就需要用单例(或准单例)的方式来访问一个Spring IoC容器。例如,第三方代码可能尝试直接构建新对象(使用Class.forName()的方式),而不从Spring IoC容器获取这些对象。如果由第三方代码创建的对象是一个stub(???存根)或代理,然后使用单例的方式访问Spring容器来获取被代理的真正对象,那么主要的代码依然达成了控制反转(这个对象从容器得到)。因此大部分代码仍然不知道容器或者如何访问它,并且保持了与其它代码的解耦和随之而来的所有好处。EJB可以使用这种存根/代理的方法来代理一个从Spring IoC容器检索出来的普通Java对象。虽然Spring IoC容器本身不一定非要是一个单例,但在内存使用或初始化时间(在Spring IoC容器中使用bean例如一个Hibernate SessionFactory)方面,每个bean使用自己的、非单例Spring IoC容器是不切实际的。

用服务定位器的方法检索应用上下文有时是获取共享Spring管理组件的唯一方式,例如在EJB 2.1环境中或者当你想共享一个ApplicationContext作为另一个WAR文件的WebApplicationContext的父上下文。在这种情况下需要查看工具类ContextSingletonBeanFactoryLocator定位器。

展开阅读全文
加载中

作者的其它热门文章

打赏
0
0 收藏
分享
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部