Verschil tussen BeanFactory en ApplicationContext

1. Overzicht

Het Spring Framework wordt geleverd met twee IOC-containers - BeanFactory en ApplicationContext. De BeanFactory is de meest eenvoudige versie van IOC-containers, en de ApplicationContext breidt de kenmerken van BeanFactory.

In deze korte tutorial zullen we de significante verschillen tussen deze twee IOC-containers begrijpen met praktische voorbeelden.

2. Lui laden versus gretig laden

BeanFactory laadt bonen op aanvraag, terwijl ApplicationContext laadt alle bonen bij het opstarten. Dus, BeanFactory is lichtgewicht in vergelijking met ApplicationContext. Laten we het begrijpen met een voorbeeld.

2.1. Lui laden met BeanFactory

Laten we aannemen dat we een singleton bean-klasse hebben genaamd Leerling met één methode:

openbare klasse Student {openbare statische boolean isBeanInstantiated = false; openbare ongeldige postConstruct () {setBeanInstantiated (true); } // standaard setters en getters}

We zullen de postConstruct () methode als de init-methode in onze BeanFactory configuratiebestand, ioc-container-different-example.xml:

Laten we nu een testcase schrijven die een BeanFactory om te controleren of het Leerling Boon:

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

Hier, de Leerling object is niet geïnitialiseerd. Met andere woorden, alleen de BeanFactory wordt geïnitialiseerd. De bonen gedefinieerd in ons BeanFactory wordt alleen geladen als we expliciet de getBean () methode.

Laten we de initialisatie van onze Leerling bean waar we handmatig de getBean () methode:

@Test public void whenBFInitialized_thenStudentInitialized () {Resource res = new ClassPathResource ("ioc-container-different-example.xml"); BeanFactory factory = nieuwe XmlBeanFactory (res); Student student = (Student) factory.getBean ("student"); assertTrue (Student.isBeanInstantiated ()); }

Hier de Leerling bean laadt succesvol. Vandaar dat de BeanFactory laadt de boon alleen als dat nodig is.

2.2. Gretig laden met ApplicationContext

Laten we nu gebruiken ApplicationContext in plaats van BeanFactory.

We zullen alleen definiëren Toepassingscontext, en het laadt alle bonen onmiddellijk door een gretige laadstrategie te gebruiken:

@Test openbare leegte whenAppContInitialized_thenStudentInitialized () {ApplicationContext context = nieuwe ClassPathXmlApplicationContext ("ioc-container-verschil-voorbeeld.xml"); assertTrue (Student.isBeanInstantiated ()); }

Hier de Leerling object wordt gemaakt, ook al hebben we de getBean () methode.

ApplicationContext wordt beschouwd als een zware IOC-container omdat de gretige laadstrategie alle bonen bij het opstarten laadt. BeanFactory is in vergelijking licht van gewicht en kan handig zijn in systemen met een beperkt geheugen. Niettemin, we zullen in de volgende secties zien waarom ApplicationContext heeft in de meeste gevallen de voorkeur.

3. Functies van bedrijfstoepassingen

ApplicationContext verbetert BeanFactory in een meer framework-georiënteerde stijl en biedt verschillende functies die geschikt zijn voor bedrijfstoepassingen.

Het biedt messaging (i18n of internationalisering) functionaliteit, evenement publicatie functionaliteit, op annotatie gebaseerde afhankelijkheidsinjectie, en eenvoudige integratie met Spring AOP-functies.

Afgezien van dit, de ApplicationContext ondersteunt bijna alle soorten bean scopes, maar de BeanFactory ondersteunt slechts twee scopes - Singleton en Voorlopig ontwerp. Daarom is het altijd beter om te gebruiken ApplicationContext bij het bouwen van complexe bedrijfsapplicaties.

4. Automatische registratie van BeanFactoryPostProcessor en BeanPostProcessor

De ApplicationContext registreert automatisch BeanFactoryPostProcessor en BeanPostProcessor in de beginfase. Aan de andere kant is het BeanFactory registreert deze interfaces niet automatisch.

4.1. Registratie in BeanFactory

Laten we, om het te begrijpen, twee lessen schrijven.

Ten eerste hebben we de CustomBeanFactoryPostProcessor class, die de BeanFactoryPostProcessor:

openbare klasse CustomBeanFactoryPostProcessor implementeert BeanFactoryPostProcessor {privé statische boolean isBeanFactoryPostProcessorRegistered = false; @Override openbare ongeldige postProcessBeanFactory (ConfigurableListableBeanFactory beanFactory) {setBeanFactoryPostProcessorRegistered (true); } // standaard setters en getters}

Hier hebben we de postProcessBeanFactory () methode om de registratie te controleren.

Ten tweede hebben we nog een klas, CustomBeanPostProcessor, die implementeert BeanPostProcessor:

openbare klasse CustomBeanPostProcessor implementeert BeanPostProcessor {privé statische boolean isBeanPostProcessorRegistered = false; @Override openbaar object postProcessBeforeInitialization (Object bean, String beanName) {setBeanPostProcessorRegistered (true); terugkeer boon; } // standaard setters en getters}

Hier hebben we de postProcessBeforeInitialization () methode om de registratie te controleren.

We hebben ook beide klassen geconfigureerd in ons ioc-container-different-example.xml configuratiebestand:

Laten we een testcase bekijken om te controleren of deze twee klassen automatisch worden geregistreerd tijdens het opstarten:

@Test openbare leegte whenBFInitialized_thenBFPProcessorAndBPProcessorNotRegAutomatically () {Resource res = new ClassPathResource ("ioc-container-different-example.xml"); ConfigurableListableBeanFactory factory = nieuwe XmlBeanFactory (res); assertFalse (CustomBeanFactoryPostProcessor.isBeanFactoryPostProcessorRegistered ()); assertFalse (CustomBeanPostProcessor.isBeanPostProcessorRegistered ()); }

Zoals we uit onze test kunnen zien, automatische registratie is niet gebeurd.

Laten we nu eens kijken naar een testcase die ze handmatig toevoegt aan het BeanFactory:

@Test openbare leegte whenBFPostProcessorAndBPProcessorRegisteredManually_thenReturnTrue () {Resource res = new ClassPathResource ("ioc-container-different-example.xml"); ConfigurableListableBeanFactory factory = nieuwe XmlBeanFactory (res); CustomBeanFactoryPostProcessor beanFactoryPostProcessor = nieuwe CustomBeanFactoryPostProcessor (); beanFactoryPostProcessor.postProcessBeanFactory (fabriek); assertTrue (CustomBeanFactoryPostProcessor.isBeanFactoryPostProcessorRegistered ()); CustomBeanPostProcessor beanPostProcessor = nieuwe CustomBeanPostProcessor (); factory.addBeanPostProcessor (beanPostProcessor); Student student = (Student) factory.getBean ("student"); assertTrue (CustomBeanPostProcessor.isBeanPostProcessorRegistered ()); }

Hier hebben we de postProcessBeanFactory () methode om te registreren CustomBeanFactoryPostProcessor en de addBeanPostProcessor () methode om te registreren CustomBeanPostProcessor. Beiden registreren zich in dit geval met succes.

4.2. Registratie in ApplicationContext

Zoals we eerder hebben opgemerkt, ApplicationContext registreert beide klassen automatisch zonder extra code te schrijven.

Laten we dit gedrag verifiëren in een unit-test:

@Test openbare leegte whenAppContInitialized_thenBFPostProcessorAndBPostProcessorRegisteredAutomatically () {ApplicationContext context = nieuwe ClassPathXmlApplicationContext ("ioc-container-verschil-voorbeeld.xml"); assertTrue (CustomBeanFactoryPostProcessor.isBeanFactoryPostProcessorRegistered ()); assertTrue (CustomBeanPostProcessor.isBeanPostProcessorRegistered ()); }

Zoals we kunnen zien, automatische inschrijving van beide klassen is succesvol in dit geval.

Daarom het is altijd raadzaam om te gebruiken ApplicationContext omdat Spring 2.0 (en hoger) zwaar gebruikt BeanPostProcessor.

Het is ook de moeite waard om dat op te merken als u de vlakte gebruikt BeanFactory, dan treden functies zoals transacties en AOP niet in werking (tenminste niet zonder extra regels code te schrijven). Dit kan tot verwarring leiden omdat niets er mis uitziet met de configuratie.

5. Conclusie

In dit artikel hebben we de belangrijkste verschillen tussen ApplicationContext en BeanFactory met praktische voorbeelden.

De ApplicationContext wordt geleverd met geavanceerde functies, waaronder een aantal die zijn gericht op bedrijfstoepassingen, terwijl de BeanFactory wordt geleverd met alleen basisfuncties. Daarom wordt over het algemeen aanbevolen om de Toepassingscontext, en we zouden moeten gebruiken BeanFactory alleen wanneer geheugengebruik kritiek is.

Zoals altijd is de code voor het artikel beschikbaar op GitHub.