Razlika između BeanFactory i ApplicationContext

1. Pregled

Spring Framework dolazi s dva kontejnera IOC - BeanFactory i ApplicationContext. The BeanFactory je najosnovnija verzija kontejnera IOC, a ApplicationContext proširuje značajke BeanFactory.

U ovom brzom vodiču razumjet ćemo značajne razlike između ova dva kontejnera MOK-a praktičnim primjerima.

2. Lijeno utovar nasuprot željnom učitavanju

BeanFactory utovari grah na zahtjev, dok ApplicationContext učitava sve mahune pri pokretanju. Tako, BeanFactory je lagan u odnosu na ApplicationContext. Shvatimo to na primjeru.

2.1. Lijeno učitavanje sa BeanFactory

Pretpostavimo da imamo jedinstvenu klasu zrna graha Student jednom metodom:

javni razred Student {javni statički logički isBeanInstantiated = false; javna void postConstruct () {setBeanInstantiated (true); } // standardni postavljači i dobivači}

Mi ćemo definirati postConstruct () metoda kao init-metoda u našem BeanFactory konfiguracijska datoteka, ioc-container-razlika-primjer.xml:

Sada, napišite test koji stvara a BeanFactory da provjeri učitava li Student grah:

@Test public void whenBFInitialized_thenStudentNotInitialized () {Resurs res = new ClassPathResource ("ioc-container-razlika-example.xml"); Tvornica BeanFactory = novi XmlBeanFactory (res); assertFalse (Student.isBeanInstantiated ()); }

Ovdje, the Student objekt nije inicijaliziran. Drugim riječima, samo BeanFactory je inicijaliziran. Grah definiran u našem BeanFactory će se učitati samo kada izričito pozovemo getBean () metoda.

Provjerimo inicijalizaciju našeg Student grah gdje ručno zovemo getBean () metoda:

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

Evo, Student grah se uspješno učitava. Dakle, BeanFactory grah učitava samo kada je to potrebno.

2.2. Željno učitavanje sa ApplicationContext

Sada, iskoristimo ApplicationContext na mjestu BeanFactory.

Mi ćemo samo definirati ApplicationContext, i odmah će učitati sav grah koristeći strategiju nestrpljivog utovara:

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

Evo, Student objekt je stvoren iako nismo pozvali getBean () metoda.

ApplicationContext smatra se teškim kontejnerom IOC-a jer njegova strategija nestrpljivog utovara učitava sve grah prilikom pokretanja. BeanFactory lagan je u usporedbi i mogao bi biti koristan u memorijski ograničenim sustavima. Štoviše, vidjet ćemo u sljedećim odjeljcima zašto ApplicationContext je poželjna za većinu slučajeva korištenja.

3. Značajke poslovne aplikacije

ApplicationContext pojačava BeanFactory u više okvirno orijentiranom stilu i pruža nekoliko značajki koje su prikladne za poslovne aplikacije.

Na primjer, to pruža razmjenu poruka (i18n ili internacionalizacija) funkcionalnost, objavljivanje događaja funkcionalnost, injekcija ovisnosti zasnovana na bilješkama, i laka integracija sa značajkama Spring AOP.

Osim ovoga, ApplicationContext podržava gotovo sve vrste opsega graha, ali BeanFactory podržava samo dva opsega - Singleton i Prototip. Stoga je uvijek poželjno koristiti ApplicationContext prilikom izrade složenih poslovnih aplikacija.

4. Automatska registracija BeanFactoryPostProcessor i BeanPostProcessor

The ApplicationContext automatski se registrira BeanFactoryPostProcessor i BeanPostProcessor pri pokretanju. S druge strane, BeanFactory ne registrira ta sučelja automatski.

4.1. Registracija u BeanFactory

Da bismo razumjeli, napišimo dva razreda.

Prvo, imamo CustomBeanFactoryPostProcessor klase koja provodi BeanFactoryPostProcessor:

javna klasa CustomBeanFactoryPostProcessor implementira BeanFactoryPostProcessor {private static boolean isBeanFactoryPostProcessorRegistered = false; @Override public void postProcessBeanFactory (ConfigurableListableBeanFactory beanFactory) {setBeanFactoryPostProcessorRegistered (true); } // standardni postavljači i dobivači}

Evo, nadjačali smo postProcessBeanFactory () način provjere njegove registracije.

Drugo, imamo još jedan razred, CustomBeanPostProcessor, koji provodi BeanPostProcessor:

javna klasa CustomBeanPostProcessor implementira BeanPostProcessor {private static boolean isBeanPostProcessorRegistered = false; @Override public Object postProcessBeforeInitialization (Object bean, String beanName) {setBeanPostProcessorRegistered (true); grah za povratak; } // standardni postavljači i dobivači}

Evo, nadjačali smo postProcessBeforeInitialization () način provjere njegove registracije.

Također, konfigurirali smo obje klase u našem ioc-container-razlika-primjer.xml konfiguracijska datoteka:

Pogledajmo test slučaja kako bismo provjerili jesu li ove dvije klase automatski registrirane tijekom pokretanja:

@Test public void whenBFInitialized_thenBFPProcessorAndBPProcessorNotRegAutomatically () {Resurs res = new ClassPathResource ("ioc-container-razlika-example.xml"); ConfigurableListableBeanFactory tvornica = nova XmlBeanFactory (res); assertFalse (CustomBeanFactoryPostProcessor.isBeanFactoryPostProcessorRegistered ()); assertFalse (CustomBeanPostProcessor.isBeanPostProcessorRegistered ()); }

Kao što možemo vidjeti iz našeg testa, automatska registracija se nije dogodila.

Sada, pogledajmo test koji ih ručno dodaje u BeanFactory:

@Test public void whenBFPostProcessorAndBPProcessorRegisteredManually_thenReturnTrue () {Resurs res = novi ClassPathResource ("ioc-container-razlika-example.xml"); ConfigurableListableBeanFactory tvornica = nova XmlBeanFactory (res); CustomBeanFactoryPostProcessor beanFactoryPostProcessor = novi CustomBeanFactoryPostProcessor (); beanFactoryPostProcessor.postProcessBeanFactory (tvornica); assertTrue (CustomBeanFactoryPostProcessor.isBeanFactoryPostProcessorRegistered ()); CustomBeanPostProcessor beanPostProcessor = novi CustomBeanPostProcessor (); factory.addBeanPostProcessor (beanPostProcessor); Student student = (Student) factory.getBean ("student"); assertTrue (CustomBeanPostProcessor.isBeanPostProcessorRegistered ()); }

Ovdje smo koristili postProcessBeanFactory () metoda za registraciju CustomBeanFactoryPostProcessor i addBeanPostProcessor () metoda za registraciju CustomBeanPostProcessor. Oboje su se uspješno registrirali u ovom slučaju.

4.2. Registracija u ApplicationContext

Kao što smo ranije primijetili, ApplicationContext automatski registrira obje klase bez pisanja dodatnog koda.

Provjerimo ovo ponašanje u jediničnom testu:

@Test public void whenAppContInitialized_thenBFPostProcessorAndBPostProcessorRegisteredAutomatically () {ApplicationContext context = new ClassPathXmlApplicationContext ("ioc-container-razlika-example.xml"); assertTrue (CustomBeanFactoryPostProcessor.isBeanFactoryPostProcessorRegistered ()); assertTrue (CustomBeanPostProcessor.isBeanPostProcessorRegistered ()); }

Kao što vidimo, automatska registracija obje klase je uspješna u ovom slučaju.

Stoga, uvijek je preporučljivo koristiti ApplicationContext jer Spring 2.0 (i noviji) intenzivno koristi BeanPostProcessor.

To je također vrijedno napomenuti ako se koristite ravnicom BeanFactory, tada značajke poput transakcija i AOP-a neće stupiti na snagu (barem ne bez pisanja dodatnih redaka koda). To može dovesti do zabune jer ništa neće izgledati pogrešno s konfiguracijom.

5. Zaključak

U ovom smo članku vidjeli ključne razlike između ApplicationContext i BeanFactory s praktičnim primjerima.

The ApplicationContext dolazi s naprednim značajkama, uključujući nekoliko koje su usmjerene na poslovne programe, dok BeanFactory dolazi sa samo osnovnim značajkama. Stoga se općenito preporučuje korištenje ApplicationContext, i trebali bismo koristiti BeanFactory samo kada je potrošnja memorije kritična.

Kao i uvijek, kôd članka dostupan je na GitHub-u.