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:
<bean id="student" class="com.baeldung.ioccontainer.bean.Student" init-method="postConstruct"/>
当初,让咱们编写一个测试用例来创立一个BeanFactory 来查看它是否加载了Student bean:
@Testpublic 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() 办法:
@Testpublic 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:
@Testpublic void whenAppContInitialized_thenStudentInitialized() { ApplicationContext context = new ClassPathXmlApplicationContext("ioc-container-difference-example.xml"); assertTrue(Student.isBeanInstantiated());}
在这里,即便咱们没有调用 getBean() 办法,也会创立 Student 对象
ApplicationContext 被认为是一个惨重的IOC容器,因为它的预加载策略在启动时加载所有bean。相比之下,BeanFactory 是轻量级的,在内存受限的零碎中十分不便。尽管如此,大多数用例依然首选应用 ApplicationContext,这是为什么呢?
3. 企业应用程序性能
ApplicationContext 以更面向框架的格调加强了BeanFactory,并提供了一些实用于企业应用程序的性能。
例如,它提供了消息传递(i18n或国际化)性能、事件公布性能、基于正文的依赖注入,以及与Spring AOP个性的简略集成。
除此之外,ApplicationContext简直反对所有类型的 bean 作用域,然而BeanFactory只反对两个作用域——Singleton和Prototype。因而,在构建简单的企业应用程序时,最好应用ApplicationContext。
4. 主动注册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 配置文件中配置了这两个类:
<bean id="customBeanPostProcessor" class="com.baeldung.ioccontainer.bean.CustomBeanPostProcessor" /><bean id="customBeanFactoryPostProcessor" class="com.baeldung.ioccontainer.bean.CustomBeanFactoryPostProcessor" />
让咱们看一个测试用例来查看这两个类是否在启动期间主动注册:
@Testpublic void whenBFInitialized_thenBFPProcessorAndBPProcessorNotRegAutomatically() { Resource res = new ClassPathResource("ioc-container-difference-example.xml"); ConfigurableListableBeanFactory factory = new XmlBeanFactory(res); assertFalse(CustomBeanFactoryPostProcessor.isBeanFactoryPostProcessorRegistered()); assertFalse(CustomBeanPostProcessor.isBeanPostProcessorRegistered());}
从咱们的测试中咱们能够看到,主动注册并没有产生。
当初,让咱们看看一个测试用例,手动将它们增加到 BeanFactory:
@Testpublic 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会主动注册这两个类,而无需编写额定的代码。
让咱们在单元测试中验证此行为:
@Testpublic void whenAppContInitialized_thenBFPostProcessorAndBPostProcessorRegisteredAutomatically() { ApplicationContext context = new ClassPathXmlApplicationContext("ioc-container-difference-example.xml"); assertTrue(CustomBeanFactoryPostProcessor.isBeanFactoryPostProcessorRegistered()); assertTrue(CustomBeanPostProcessor.isBeanPostProcessorRegistered());}
咱们能够看到,这两个类的主动注册都是胜利的。
因而,倡议应用ApplicationContext,因为Spring2.0(及更高版本)大量应用BeanPostProcessor。
还有一点值得注意的是如果应用的是一般的 BeanFactory,那么事务和AOP之类的性能将不会失效(除非你编写额定的代码实现,那就另当别论了)。这样可能会导致代码很凌乱,因为配置看起来貌似没故障。
5. 写在结尾
ApplicationContext 提供了一些高级性能,包含一些面向企业应用程序的性能,而BeanFactory只提供了基本功能。因而,个别倡议应用 ApplicationContext ,只有在内存耗费十分要害的状况下,咱们才应该思考去应用BeanFactory。
如果你感觉文章还不错,记得关注公众号: 锅外的大佬
刘一手的博客