Spring IOC之BeanFactory

时间:2023-03-09 02:24:20
Spring IOC之BeanFactory

BeanFactory提供了SpringIOC功能的基础但是它只是直接在用在和第三方框架的整合中,而且现在对于大部分的Spring用户来讲这一句成为了过去。BeanFactory和相关的接口,例如BeanFactoryAware、InitializingBean、DisposalBean,仍然在Spring中用于向后的兼容大量的和Spring整合的第三方框架。为了和JDK1.4保存兼容或者避免依赖JSR-250,通常第三方的组件不能做到完全意义上的等价,比如 @PostConstruct 或者 @PreDestroy。

这部分谈到了BeanFactory和AppliationContext中的背景不同和通过单例查找中直接的访问IOC容器。

1.BeanFactory还是ApplicationContext?

除非你有更好的理由不去使用它,否则就使用ApplicationContext。

因为ApplicationContext包含了BeanFactory所有的功能,只有在用一些很少的方案中才会建议是BeanFactory,例如当内存计算很关键的Applet中,或者一些额外的千字节可能有作用的地方。但是,对于大部分的企业级应用和系统中,ApplicationContext就是你想使用的那个。如果你只是使用了普通的BeanFactory,大量的例如事务和AOP就不会起作用,至少在没有其他额外的作用下不会起作用。这种方法可能会让你疑惑因为没有东西会在配置中出错。

下面的表格中的功能就是BeanFactory和ApplicationContext接口提供和实现的:

功能 BeanFactory ApplicationContext
Bean的实例化
自动的BeanPostProcessor注册
自动的BeanFactoryPostProcessor注册
可用的MessageSource(国际化)
ApplicationEvent发布

为了显示的用一个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);

在上面的两个例子中,显示的注册都是不可用的,这也是在大部分的基于Spring的引用中,特别是当使用BeanFactoryPostProcessors 和BeanPostProcessors的时候为什么不同的ApplicationContext的实现是相对于普通的BeanFactory更愿意被使用的原因之一。

2.耦合代码和邪恶的单例

最好是以一种DI的风格来写大部分的应用代码在SpringIOC容器的外部,这样在它被创建的时候它就会拥有容器提供的自己的依赖,而且不会通知容器。但是对于一小部分耦合的代码有时候需要将其他的代码绑定在一起,你有时候需要通过一个单例来访问Spring的IOC容器。例如,第三方框架可能不适用Spring IOC容器获取对象的能力而直接构建对象。如果通过第三方框架代码构建的对象是一个小的代理,它就会使用单例去访问Spring IOC容器去获取真实代理的对象,然后控制反转对于大部分的代码还是有作用的。所以大部分的代码任务不告诉容器或者它是怎么访问的,而且仍然和其他的代码实现解耦。EJBs坑内使用这个代理的方式去委托给一个普通的实现的java对象,或者从一个Spring IOC容器检出的对象。尽管Spring IOC容器可能是自己没有必要是单例,但是就内存使用和每一个bean使用它自己的分单例的Spring IOC容器的实例化次数而言,这个可能是不现实的。

以服务定位器的方式来查看应用上下文是访问共享spring管理的组件的唯一选项,比如EJB2.1环境,或者是当你想通过WAR文件共享一个单独的ApplicationContext作为WebApplicationContext的父类。