Forskellen mellem BeanFactory og ApplicationContext

1. Oversigt

Spring Framework leveres med to IOC-containere - BeanFactory og ApplicationContext. Det BeanFactory er den mest grundlæggende version af IOC-containere, og ApplicationContext udvider funktionerne i BeanFactory.

I denne hurtige vejledning forstår vi de væsentlige forskelle mellem disse to IOC-containere med praktiske eksempler.

2. Lazy Loading vs. Eager Loading

BeanFactory indlæser bønner efter behov, mens ApplicationContext indlæser alle bønner ved opstart. Dermed, BeanFactory er let i forhold til ApplicationContext. Lad os forstå det med et eksempel.

2.1. Lazy Loading With BeanFactory

Lad os antage, at vi har en singleton bønne klasse kaldet Studerende med en metode:

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

Vi definerer postConstruct () metode som init-metode i vores BeanFactory konfigurationsfil, ioc-container-forskel-eksempel.xml:

Lad os nu skrive en test sag, der skaber en BeanFactory for at kontrollere, om den indlæser Studerende bønne:

@Test offentlig ugyldigt nårBFInitialized_thenStudentNotInitialized () {Resource res = new ClassPathResource ("ioc-container-difference-example.xml"); BeanFactory fabrik = ny XmlBeanFactory (res); assertFalse (Student.isBeanInstantiated ()); }

Her, det Studerende objektet initialiseres ikke. Med andre ord, kun den BeanFactory er initialiseret. De bønner, der er defineret i vores BeanFactory vil kun blive indlæst, når vi udtrykkeligt kalder getBean () metode.

Lad os kontrollere initialiseringen af ​​vores Studerende hvor vi manuelt kalder getBean () metode:

@Test offentligt ugyldigt nårBFInitialized_thenStudentInitialized () {Resource res = new ClassPathResource ("ioc-container-difference-example.xml"); BeanFactory fabrik = ny XmlBeanFactory (res); Studerende studerende = (Student) factory.getBean ("student"); assertTrue (Student.isBeanInstantiated ()); }

Her, den Studerende bønne belastes med succes. Derfor er den BeanFactory indlæser kun bønnen, når det er nødvendigt.

2.2. Ivrig lastning med ApplicationContext

Lad os nu bruge det ApplicationContext i stedet for BeanFactory.

Vi definerer kun ApplicationContext, og det vil indlæse alle bønner med det samme ved hjælp af en ivrig-loading-strategi:

@Test offentlig ugyldig, nårAppContInitialized_thenStudentInitialized () {ApplicationContext context = new ClassPathXmlApplicationContext ("ioc-container-difference-example.xml"); assertTrue (Student.isBeanInstantiated ()); }

Her, den Studerende objekt oprettes, selvom vi ikke har kaldt getBean () metode.

ApplicationContext betragtes som en tung IOC-container, fordi strategien for ivrig indlæsning indlæser alle bønner ved opstart. BeanFactory er let ved sammenligning og kan være praktisk i hukommelsesbegrænsede systemer. Alligevel, vi får se i de næste afsnit hvorfor ApplicationContext foretrækkes i de fleste brugssager.

3. Enterprise-applikationsfunktioner

ApplicationContext forbedrer BeanFactory i en mere rammeorienteret stil og giver flere funktioner, der er egnede til virksomhedsapplikationer.

For eksempel det giver messaging (i18n eller internationalisering) funktionalitet, begivenhedspublikation funktionalitet, annoteringsbaseret afhængighedsinjektionog nem integration med Spring AOP-funktioner.

Bortset fra dette, den ApplicationContext understøtter næsten alle typer af bønneomfang, men BeanFactory understøtter kun to anvendelsesområder - Singleton og Prototype. Derfor er det altid at foretrække at bruge ApplicationContext når man bygger komplekse virksomhedsapplikationer.

4. Automatisk registrering af BeanFactoryPostProcessor og BeanPostProcessor

Det ApplicationContext automatisk registreres BeanFactoryPostProcessor og BeanPostProcessor ved opstart. På den anden side er BeanFactory registrerer ikke disse grænseflader automatisk.

4.1. Registrering i BeanFactory

For at forstå, lad os skrive to klasser.

For det første har vi CustomBeanFactoryPostProcessor klasse, der implementerer BeanFactoryPostProcessor:

offentlig klasse CustomBeanFactoryPostProcessor implementerer BeanFactoryPostProcessor {privat statisk boolsk isBeanFactoryPostProcessorRegistered = false; @ Overstyr offentlig ugyldig postProcessBeanFactory (ConfigurableListableBeanFactory beanFactory) {setBeanFactoryPostProcessorRegistered (true); } // standard settere og getters}

Her har vi tilsidesat postProcessBeanFactory () metode til at kontrollere dets registrering.

For det andet har vi en anden klasse, CustomBeanPostProcessor, som implementerer BeanPostProcessor:

offentlig klasse CustomBeanPostProcessor implementerer BeanPostProcessor {privat statisk boolsk isBeanPostProcessorRegistered = false; @Override public Object postProcessBeforeInitialization (Object bean, String beanName) {setBeanPostProcessorRegistered (true); retur bønne; } // standard settere og getters}

Her har vi tilsidesat postProcessBeforeInitialization () metode til at kontrollere dets registrering.

Vi har også konfigureret begge klasser i vores ioc-container-forskel-eksempel.xml konfigurationsfil:

Lad os se en test case for at kontrollere, om disse to klasser registreres automatisk under opstart:

@Test offentlig ugyldig nårBFInitialized_thenBFPProcessorAndBPProcessorNotRegAutomatically () {Resource res = new ClassPathResource ("ioc-container-difference-example.xml"); ConfigurableListableBeanFactory fabrik = ny XmlBeanFactory (res); assertFalse (CustomBeanFactoryPostProcessor.isBeanFactoryPostProcessorRegistered ()); assertFalse (CustomBeanPostProcessor.isBeanPostProcessorRegistered ()); }

Som vi kan se fra vores test, automatisk registrering skete ikke.

Lad os nu se en test sag, der manuelt tilføjer dem i BeanFactory:

@Test offentlig ugyldigt nårBFPostProcessorAndBPProcessorRegisteredManually_thenReturnTrue () {Resource res = new ClassPathResource ("ioc-container-difference-example.xml"); ConfigurableListableBeanFactory fabrik = ny XmlBeanFactory (res); CustomBeanFactoryPostProcessor beanFactoryPostProcessor = ny CustomBeanFactoryPostProcessor (); beanFactoryPostProcessor.postProcessBeanFactory (fabrik); assertTrue (CustomBeanFactoryPostProcessor.isBeanFactoryPostProcessorRegistered ()); CustomBeanPostProcessor beanPostProcessor = ny CustomBeanPostProcessor (); factory.addBeanPostProcessor (beanPostProcessor); Studerende studerende = (Student) factory.getBean ("student"); assertTrue (CustomBeanPostProcessor.isBeanPostProcessorRegistered ()); }

Her brugte vi postProcessBeanFactory () metode til registrering CustomBeanFactoryPostProcessor og addBeanPostProcessor () metode til registrering CustomBeanPostProcessor. Begge registrerer sig med succes i dette tilfælde.

4.2. Registrering i ApplicationContext

Som vi bemærkede tidligere, ApplicationContext registrerer begge klasser automatisk uden at skrive yderligere kode.

Lad os kontrollere denne adfærd i en enhedstest:

@Test offentlig ugyldig, nårAppContInitialized_thenBFPostProcessorAndBPostProcessorRegisteredAutomatically () {ApplicationContext context = new ClassPathXmlApplicationContext ("ioc-container-forskel-eksempel.xml"); assertTrue (CustomBeanFactoryPostProcessor.isBeanFactoryPostProcessorRegistered ()); assertTrue (CustomBeanPostProcessor.isBeanPostProcessorRegistered ()); }

Som vi kan se, automatisk registrering af begge klasser er vellykket I dette tilfælde.

Derfor, det er altid tilrådeligt at bruge ApplicationContext fordi Spring 2.0 (og derover) bruger meget BeanPostProcessor.

Det er også værd at bemærke det hvis du bruger sletten BønneFabrik, så vil funktioner som transaktioner og AOP ikke træde i kraft (i det mindste ikke uden at skrive ekstra kodelinjer). Dette kan føre til forvirring, fordi intet ser forkert ud med konfigurationen.

5. Konklusion

I denne artikel har vi set de vigtigste forskelle mellem ApplicationContext og BeanFactory med praktiske eksempler.

Det ApplicationContext leveres med avancerede funktioner, herunder flere, der er rettet mod virksomhedsapplikationer, mens BeanFactory leveres med kun grundlæggende funktioner. Derfor anbefales det generelt at bruge ApplicationContext, og vi skal bruge BeanFactory kun når hukommelsesforbruget er kritisk.

Som altid er artiklens kode tilgængelig på GitHub.