Unterschied zwischen BeanFactory und ApplicationContext

1. Übersicht

Das Spring Framework enthält zwei IOC-Container - BeanFactory und ApplicationContext . Die BeanFactory ist die grundlegendste Version von IOC-Containern, und der ApplicationContext erweitert die Funktionen von BeanFactory .

In diesem kurzen Tutorial werden wir die signifikanten Unterschiede zwischen diesen beiden IOC-Containern anhand praktischer Beispiele verstehen.

2. Lazy Loading vs. Eager Loading

BeanFactory lädt Beans bei Bedarf, während ApplicationContext beim Start alle Beans lädt . Somit ist BeanFactory im Vergleich zu ApplicationContext leichtgewichtig. Lassen Sie es uns anhand eines Beispiels verstehen.

2.1. Faules Laden mit BeanFactory

Nehmen wir an, wir haben eine Singleton-Bean-Klasse namens Student mit einer Methode:

public class Student { public static boolean isBeanInstantiated = false; public void postConstruct() { setBeanInstantiated(true); } //standard setters and getters }

Wir definieren die postConstruct () -Methode als init-Methode in unserer BeanFactory- Konfigurationsdatei ioc-container-different-example.xml :

Schreiben wir nun einen Testfall, der eine BeanFactory erstellt , um zu überprüfen, ob die Student- Bean geladen wird :

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

Hier wird das Student- Objekt nicht initialisiert . Mit anderen Worten, nur die BeanFactory wird initialisiert . Die in unserer BeanFactory definierten Beans werden nur geladen, wenn wir die Methode getBean () explizit aufrufen .

Lassen Sie uns die Initialisierung unserer Student- Bean überprüfen, in der wir die Methode getBean () manuell aufrufen :

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

Hier wird die Student Bean erfolgreich geladen. Daher lädt die BeanFactory die Bean nur, wenn dies erforderlich ist.

2.2. Eifriges Laden mit ApplicationContext

Verwenden wir jetzt ApplicationContext anstelle von BeanFactory.

Wir definieren nur ApplicationContext und es werden alle Beans sofort geladen, indem eine Eifrig-Ladestrategie verwendet wird:

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

Hier wird das Student- Objekt erstellt, obwohl wir die Methode getBean () nicht aufgerufen haben .

ApplicationContext wird als schwerer IOC-Container angesehen, da durch seine Strategie des eifrigen Ladens alle Beans beim Start geladen werden. BeanFactory ist im Vergleich leicht und kann in Systemen mit eingeschränktem Speicher nützlich sein. Trotzdem werden wir in den nächsten Abschnitten sehen , warum Application für die meisten Anwendungsfälle bevorzugt wird .

3. Funktionen der Unternehmensanwendung

Application verbessert BeanFactory in einem Rahmen-orientierten Stil und bietet mehrere Funktionen , die für Enterprise - Anwendungen geeignet sind.

Beispielsweise bietet es Messaging-Funktionen (i18n oder Internationalisierung), Funktionen zur Ereignisveröffentlichung , annotationsbasierte Abhängigkeitsinjektion und eine einfache Integration in Spring AOP-Funktionen .

Abgesehen davon unterstützt der ApplicationContext fast alle Arten von Bean-Bereichen, aber die BeanFactory unterstützt nur zwei Bereiche - Singleton und Prototype . Daher ist es immer vorzuziehen, ApplicationContext beim Erstellen komplexer Unternehmensanwendungen zu verwenden.

4. Automatische Registrierung von BeanFactoryPostProcessor und BeanPostProcessor

Der ApplicationContext registriert BeanFactoryPostProcessor und BeanPostProcessor beim Start automatisch . Andererseits registriert die BeanFactory diese Schnittstellen nicht automatisch.

4.1. Registrierung in BeanFactory

Um dies zu verstehen, schreiben wir zwei Klassen.

Erstens haben wir die CustomBeanFactoryPostProcessor- Klasse, die den BeanFactoryPostProcessor implementiert :

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

Hier haben wir die postProcessBeanFactory () -Methode überschrieben , um ihre Registrierung zu überprüfen.

Zweitens haben wir eine andere Klasse, CustomBeanPostProcessor , die BeanPostProcessor implementiert :

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 }

Hier haben wir die postProcessBeforeInitialization () -Methode überschrieben , um ihre Registrierung zu überprüfen.

Außerdem haben wir beide Klassen in unserer Konfigurationsdatei ioc-container-different-example.xml konfiguriert:

Sehen wir uns einen Testfall an, um zu überprüfen, ob diese beiden Klassen beim Start automatisch registriert werden:

@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:

@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.

4.2. Registration in ApplicationContext

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

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.

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.

5. Conclusion

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

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.

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