Difference Between BeanFactory and ApplicationContext – BeanFactory和ApplicationContext之间的区别

最后修改: 2020年 4月 1日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

The Spring Framework comes with two IOC containers – BeanFactory and ApplicationContext. The BeanFactory is the most basic version of IOC containers, and the ApplicationContext extends the features of BeanFactory.

Spring框架带有两个IOC容器–BeanFactoryApplicationContextBeanFactory是IOC容器的最基本版本,而ApplicationContext扩展了BeanFactory的功能。

In this quick tutorial, we’ll understand the significant differences between these two IOC containers with practical examples.

在这个快速教程中,我们将通过实际例子了解这两种IOC容器之间的显著区别。

2. Lazy Loading vs. Eager Loading

2.懒惰的加载与急切的加载

BeanFactory loads beans on-demand, while ApplicationContext loads all beans at startup. Thus, BeanFactory is lightweight as compared to ApplicationContext. Let’s understand it with an example.

BeanFactory按需加载bean,而ApplicationContext在启动时加载所有bean。因此,BeanFactoryApplicationContext相比是轻量级的。让我们通过一个例子来理解它。

2.1. Lazy Loading With BeanFactory

2.1.使用BeanFactory进行懒散加载

Let’s suppose we have a singleton bean class called Student with one method:

假设我们有一个singleton bean类,叫做Student,有一个方法。

public class Student {
    public static boolean isBeanInstantiated = false;

    public void postConstruct() {
        setBeanInstantiated(true);
    }

    //standard setters and getters
}

We’ll define the postConstruct() method as the init-method in our BeanFactory configuration file, ioc-container-difference-example.xml:

我们将在我们的BeanFactory配置文件ioc-container-difference-example.xml中把postConstruct()方法定义为init-method

<bean id="student" class="com.baeldung.ioccontainer.bean.Student" init-method="postConstruct"/>

Now, let’s write a test case that creates a BeanFactory to check if it loads the Student bean:

现在,让我们写一个测试用例,创建一个BeanFactory来检查它是否加载了Student bean。

@Test
public void whenBFInitialized_thenStudentNotInitialized() {
    Resource res = new ClassPathResource("ioc-container-difference-example.xml");
    BeanFactory factory = new XmlBeanFactory(res);
    
    assertFalse(Student.isBeanInstantiated());
}

Here, the Student object is not initialized. In other words, only the BeanFactory is initialized. The beans defined in our BeanFactory will be loaded only when we explicitly call the getBean() method.

这里,Student对象没有被初始化。换句话说,只有BeanFactory被初始化了。只有当我们明确地调用getBean()方法时,在我们的BeanFactory中定义的Bean才会被加载

Let’s check the initialization of our Student bean where we’re manually calling the getBean() method:

让我们检查一下我们的Studentbean的初始化,在这里我们手动调用getBean()方法。

@Test
public 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());
}

Here, the Student bean loads successfully. Hence, the BeanFactory only loads the bean when it is required.

在这里,Student bean成功加载。因此,BeanFactory只在需要时才加载Bean。

2.2. Eager Loading With ApplicationContext

2.2.用ApplicationContext急切加载

Now, let’s use ApplicationContext in the place of BeanFactory.

现在,让我们用ApplicationContext 来代替BeanFactory。

We’ll only define ApplicationContext, and it will load all the beans instantly by using an eager-loading strategy:

我们将只定义ApplicationContext,并且它将通过使用急迫加载策略即时加载所有的bean。

@Test
public void whenAppContInitialized_thenStudentInitialized() {
    ApplicationContext context = new ClassPathXmlApplicationContext("ioc-container-difference-example.xml");
    
    assertTrue(Student.isBeanInstantiated());
}

Here, the Student object is created even though we have not called the getBean() method.

在这里,尽管我们没有调用getBean()方法,但Student对象还是被创建了。

ApplicationContext is considered a heavy IOC container because its eager-loading strategy loads all the beans at startup. BeanFactory is lightweight by comparison and could be handy in memory-constrained systems. Nevertheless, we’ll see in the next sections why ApplicationContext is preferred for most use cases.

ApplicationContext被认为是一个沉重的IOC容器,因为它的急切加载策略在启动时加载所有的Bean。相比之下,BeanFactory是轻量级的,在内存受限的系统中可能会很方便。尽管如此,我们将在接下来的章节中看到为什么ApplicationContext在大多数用例中是首选

3. Enterprise Application Features

3.企业应用功能

ApplicationContext enhances BeanFactory in a more framework-oriented style and provides several features that are suitable for enterprise applications.

ApplicationContext以更加面向框架的风格增强了BeanFactory,并提供了几个适合企业应用的功能。

For instance, it provides messaging (i18n or internationalization) functionality, event publication functionality, annotation-based dependency injection, and easy integration with Spring AOP features.

例如,它提供消息传递(i18n或国际化)功能、事件发布功能、基于注释的依赖注入,以及与Spring AOP特性轻松集成

Apart from this, the ApplicationContext supports almost all types of bean scopes, but the BeanFactory only supports two scopes — Singleton and Prototype. Therefore, it’s always preferable to use ApplicationContext when building complex enterprise applications.

除此之外,ApplicationContext支持几乎所有类型的bean作用域,但是BeanFactory只支持两个作用域–SingletonPrototype。因此,在构建复杂的企业应用程序时,最好是使用ApplicationContext

4. Automatic Registration of BeanFactoryPostProcessor and BeanPostProcessor

4.自动注册BeanFactoryPostProcessorBeanPostProcessor

The ApplicationContext automatically registers BeanFactoryPostProcessor and BeanPostProcessor at startup. On the other hand, the BeanFactory does not register these interfaces automatically.

ApplicationContext在启动时自动注册了BeanFactoryPostProcessorBeanPostProcessor。另一方面,BeanFactory不会自动注册这些接口。

4.1. Registration in BeanFactory

4.1.在BeanFactory中注册

To understand, let’s write two classes.

为了理解,我们来写两个类。

Firstly, we have the CustomBeanFactoryPostProcessor class, which implements the BeanFactoryPostProcessor:

首先,我们有CustomBeanFactoryPostProcessor类,它实现了BeanFactoryPostProcessor

public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    private static boolean isBeanFactoryPostProcessorRegistered = false;
    
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory){
        setBeanFactoryPostProcessorRegistered(true);
    }

    // standard setters and getters
}

Here, we’ve overridden the postProcessBeanFactory() method to check its registration.

在这里,我们重载了postProcessBeanFactory()方法来检查其注册情况。

Secondly, we have another class, CustomBeanPostProcessor, which implements BeanPostProcessor:

其次,我们有另一个类,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
}

Here, we’ve overridden the postProcessBeforeInitialization() method to check its registration.

在这里,我们重载了postProcessBeforeInitialization()方法以检查其注册。

Also, we’ve configured both the classes in our ioc-container-difference-example.xml configuration file:

另外,我们已经在ioc-container-difference-example.xml 配置文件中配置了这两个类。

<bean id="customBeanPostProcessor" 
  class="com.baeldung.ioccontainer.bean.CustomBeanPostProcessor" />
<bean id="customBeanFactoryPostProcessor" 
  class="com.baeldung.ioccontainer.bean.CustomBeanFactoryPostProcessor" />

Let’s see a test case to check whether these two classes are registered automatically during startup:

让我们看一个测试案例,检查这两个类是否在启动时自动注册。

@Test
public void whenBFInitialized_thenBFPProcessorAndBPProcessorNotRegAutomatically() {
    Resource res = new ClassPathResource("ioc-container-difference-example.xml");
    ConfigurableListableBeanFactory factory = new XmlBeanFactory(res);

    assertFalse(CustomBeanFactoryPostProcessor.isBeanFactoryPostProcessorRegistered());
    assertFalse(CustomBeanPostProcessor.isBeanPostProcessorRegistered());
}

As we can see from our test, automatic registration did not happen.

从我们的测试中可以看出,自动注册并没有发生

Now, let’s see a test case that manually adds them in the BeanFactory:

现在,让我们看看在BeanFactory中手动添加它们的测试案例:

@Test
public 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());
}

Here, we used the postProcessBeanFactory() method to register CustomBeanFactoryPostProcessor and the addBeanPostProcessor() method to register CustomBeanPostProcessor. Both of them register successfully in this case.

在这里,我们使用postProcessBeanFactory()方法来注册CustomBeanFactoryPostProcessoraddBeanPostProcessor()方法来注册CustomBeanPostProcessor。在这种情况下,它们都注册成功了。

4.2. Registration in ApplicationContext

4.2.在ApplicationContext中注册

As we noted earlier, ApplicationContext registers both the classes automatically without writing additional code.

正如我们前面所指出的,ApplicationContext自动注册了这两个类,而无需编写额外的代码。

Let’s verify this behavior in a unit test:

让我们在一个单元测试中验证这一行为。

@Test
public void whenAppContInitialized_thenBFPostProcessorAndBPostProcessorRegisteredAutomatically() {
    ApplicationContext context 
      = new ClassPathXmlApplicationContext("ioc-container-difference-example.xml");

    assertTrue(CustomBeanFactoryPostProcessor.isBeanFactoryPostProcessorRegistered());
    assertTrue(CustomBeanPostProcessor.isBeanPostProcessorRegistered());
}

As we can see, automatic registration of both classes is successful in this case.

我们可以看到,在这种情况下,两类的自动注册是成功的

Therefore, it’s always advisable to use ApplicationContext because Spring 2.0 (and above) heavily uses BeanPostProcessor.

因此,最好使用ApplicationContext 因为Spring 2.0(及以上)大量使用BeanPostProcessor。

It’s also worth noting that if you’re using the plain BeanFactory, then features like transactions and AOP will not take effect (at least not without writing extra lines of code). This may lead to confusion because nothing will look wrong with the configuration.

还值得注意的是,如果你使用普通的BeanFactory,那么像事务和AOP这样的功能将不会生效(至少不需要编写额外的代码行)。这可能会导致混乱,因为配置看起来没有任何问题。

5. Conclusion

5.总结

In this article, we’ve seen the key differences between ApplicationContext and BeanFactory with practical examples.

在这篇文章中,我们通过实际案例看到了ApplicationContextBeanFactory之间的主要区别。

The ApplicationContext comes with advanced features, including several that are geared towards enterprise applications, while the BeanFactory comes with only basic features. Therefore, it’s generally recommended to use the ApplicationContext, and we should use BeanFactory only when memory consumption is critical.

ApplicationContext具有高级功能,包括一些面向企业应用程序的功能,而BeanFactory仅具有基本功能。因此,我们通常建议使用ApplicationContext,而只有在内存消耗严重时才应使用BeanFactory

As always, the code for the article is available over on GitHub.

一如既往,该文章的代码可在GitHub上找到。