1. 引言

Spring框架附带了两个IOC容器– BeanFactoryApplicationContext. BeanFactory是IOC容器的最根本版本,ApplicationContext扩大了BeanFactory的性能。
那么本篇文章中,咱们将通过理论例子理解这两个IOC容器之间的显著差别。

2. 提早加载 vs. 预加载

BeanFactory 按需加载bean,而 ApplicationContext 则在启动时加载所有bean。因而,BeanFactoryApplicationContext相比是轻量级的。让咱们用一个例子来了解它。

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只反对两个作用域——SingletonPrototype。因而,在构建简单的企业应用程序时,最好应用ApplicationContext

4. 主动注册BeanFactoryPostProcessorBeanPostProcessor

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。
如果你感觉文章还不错,记得关注公众号: 锅外的大佬
刘一手的博客