Différence entre BeanFactory et ApplicationContext

1. Vue d'ensemble

Spring Framework est fourni avec deux conteneurs IOC: BeanFactory et ApplicationContext . Le BeanFactory est la version la plus base des conteneurs du CIO, et le ApplicationContext étend les fonctionnalités de BeanFactory .

Dans ce rapide tutoriel, nous allons comprendre les différences significatives entre ces deux conteneurs IOC avec des exemples pratiques.

2. Chargement paresseux ou chargement hâtif

BeanFactory charges de haricots à la demande, tandis que applicationContext charge tous les haricots au démarrage . Ainsi, BeanFactory est léger par rapport à ApplicationContext . Comprenons-le avec un exemple.

2.1. Chargement paresseux avec BeanFactory

Supposons que nous ayons une classe de bean singleton appelée Student avec une méthode:

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

Nous allons définir la PostConstruct () méthode que la méthode init dans notre BeanFactory fichier de configuration, cio-conteneur différence exemple.xml :

Maintenant, écrivons un cas de test qui crée un BeanFactory pour vérifier s'il charge le bean Student :

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

Ici, l' objet Student n'est pas initialisé . En d'autres termes, seule la BeanFactory est initialisée . Les beans définis dans notre BeanFactory ne seront chargés que lorsque nous appelons explicitement la méthode getBean () .

Vérifions l'initialisation de notre bean Student où nous appelons manuellement la méthode 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()); }

Ici, le bean Student se charge avec succès. Par conséquent, BeanFactory ne charge le bean que lorsque cela est nécessaire.

2.2. Chargement impatient avec ApplicationContext

Maintenant, utilisons ApplicationContext à la place de BeanFactory.

Nous définirons uniquement ApplicationContext, et il chargera tous les beans instantanément en utilisant une stratégie de chargement impatient:

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

Ici, l' objet Student est créé même si nous n'avons pas appelé la méthode getBean () .

ApplicationContext est considéré comme un conteneur IOC lourd car sa stratégie de chargement hâtif charge tous les beans au démarrage. BeanFactory est léger en comparaison et pourrait être pratique dans les systèmes à mémoire limitée. Néanmoins, nous verrons dans les sections suivantes pourquoi ApplicationContext est préféré pour la plupart des cas d'utilisation .

3. Fonctionnalités des applications d'entreprise

ApplicationContext améliore BeanFactory dans un style plus orienté framework et fournit plusieurs fonctionnalités adaptées aux applications d'entreprise.

Par exemple, il fournit des fonctionnalités de messagerie (i18n ou internationalisation), des fonctionnalités de publication d'événements , une injection de dépendances basée sur des annotations et une intégration facile avec les fonctionnalités Spring AOP .

En dehors de cela, ApplicationContext prend en charge presque tous les types d'étendues de bean, mais BeanFactory ne prend en charge que deux étendues - Singleton et Prototype . Par conséquent, il est toujours préférable d'utiliser ApplicationContext lors de la création d'applications d'entreprise complexes.

4. Enregistrement automatique de BeanFactoryPostProcessor et BeanPostProcessor

Le ApplicationContext enregistre automatiquement BeanFactoryPostProcessor et BeanPostProcessor au démarrage. En revanche, la BeanFactory n'enregistre pas ces interfaces automatiquement.

4.1. Inscription dans BeanFactory

Pour comprendre, écrivons deux classes.

Tout d'abord, nous avons la classe CustomBeanFactoryPostProcessor , qui implémente le BeanFactoryPostProcessor :

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

Ici, nous avons remplacé la méthode postProcessBeanFactory () pour vérifier son enregistrement.

Deuxièmement, nous avons une autre classe, CustomBeanPostProcessor , qui implémente 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 }

Ici, nous avons remplacé la méthode postProcessBeforeInitialization () pour vérifier son enregistrement.

De plus, nous avons configuré les deux classes dans notre fichier de configuration ioc-container-difference-example.xml :

Voyons un cas de test pour vérifier si ces deux classes sont enregistrées automatiquement au démarrage:

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

Comme nous pouvons le voir à partir de notre test, l'enregistrement automatique n'a pas eu lieu .

Voyons maintenant un cas de test qui les ajoute manuellement dans 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()); }

Ici, nous avons utilisé la méthode postProcessBeanFactory () pour enregistrer CustomBeanFactoryPostProcessor et la méthode addBeanPostProcessor () pour enregistrer CustomBeanPostProcessor . Les deux s'enregistrent avec succès dans ce cas.

4.2. Inscription dans ApplicationContext

Comme nous l'avons noté précédemment, ApplicationContext enregistre automatiquement les deux classes sans écrire de code supplémentaire.

Vérifions ce comportement dans un test unitaire:

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