BeanFactory为Spring IoC功能提供了基础,但是了仅仅用于第三方框架的集成,并且大多数Spring使用者不怎么使用了。BeanFactory和相关的接口,比如BeanFactoryAware,InitializingBean
,DisposableBean
仍旧很常用,尤其是在Spring大量集成第三方框架中。通常第三方组件不能使用Spring最新的技术比如@PostConstruct
和@PreDestroy
来兼容JDK1.4避免JSR-250依赖。
这一部分讲述了BeanFactory和ApplicationContext之间后台的差异和哪个通过一个经典的单例查找来直接访问IoC容器。
5.1.16 BeanFactory 或 ApplicationContext?
除非你有更充足的理由不使用ApplicationContext,否则就使用它吧。
因为ApplicationContext包含了BeanFactory的所有功能,推荐使用它,除了一些情景中,比如一个Applet中,这里对于内存更加严格和更多的字节会产生一些差异。然而,对于大多数企业应用和系统中,就使用ApplicationContext。Spring会更多的使用BeanPostProcessor
扩展点(会影响代理等等)。如果仅仅使用BeanFactory,大量的功能比如AOP,事物等将不会起作用。这种情况会很使人很迷惑因为配置中没有什么错误。
下面表格列出了BeanFactory和ApplicationContext接口和实现之间的功能。
功能 | BeanFactory | ApplicationContext |
Bean实例/封装 | 是 | 是 |
自动BeanPostProcessor 注册 | no | 是 |
自动BeanFactoryPostProcessor 注册 | no | 是 |
方便的MessageSource 访问(国际化) | no | 是 |
ApplicationEvent 发布 | no | 是 |
为通过一个BeanFactory实现注册一个 bean post-processor,代码如下:
ConfigurableBeanFactory factory = new XmlBeanFactory(...);
// now register any needed BeanPostProcessor instances
MyBeanPostProcessor postProcessor = new MyBeanPostProcessor();
factory.addBeanPostProcessor(postProcessor);
// now start using the factory
使用BeanFactory实现注册一个
BeanFactoryPostProcessor
,代码如下:
XmlBeanFactory factory = new XmlBeanFactory(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);
在两个例子中,注册方式是不方便的,其中一个原因是
ApplicationContext
实现比BeanFactory在大多数Spring支持的应用程序中更加受欢迎,尤其是在使用
BeanFactoryPostProcessors
和
BeanPostProcessors
。这些机制实现了重要的功能,比如属性占位符替代和AOP。
5.16.2 粘合的代码和坏的singleton
最好以DI的方式写大多数应用程序的代码,这些代码是在Spring IoC容器外部起作用,当创建的时候,由容器提供自身依赖,并且完全不经容器提醒。然而,对于小的粘合代码层,其有时候需要与其他代码结合,有时候你需要一个singleton类型访问Spring IoC容器。例如,第三方代码需要直接构建新的对象(Class.forName()方式)
,不需要再Spring IoC容器外获取这些对象。如果由第三方代码构建的对象是一个小的stub或者代理,使用一个singleton类型访问Spring IoC容器获取委托的正真的对象,对于代码主体仍旧获取控制反转(来自容器外部的对象)。那么大多数代码仍旧不清楚容器或者如何访问和与其他代码解耦,还有随之而来的好处。EJBs可能也使用这个stub/代理方式委托给一个一身光棍的Java实现对象,这是由Spring IoC容器中重新获取的。Spring IoC容器自身理想情况下不必有一个singleton,这可能是不切实际的,在内存使用或者初始化时间方面(当在Spring IoC容器中使用beans 比如Hibernate的SessionFactory),这对于每个bean使用其自己的,不是singleton的Spring IoC容器。
在一个service locator类型中查找应用程序上下文,有时候是访问共享的Spring管理组件的唯一选择,比如EJB2.1环境中,或者当你想共享单个ApplicationContext作为WebApplicationContext的父类,贯穿WAR文件。在这个情形下,使用工具类ContextSingletonBeanFactoryLocator
locator。