Perbedaan Antara BeanFactory dan ApplicationContext

1. Ikhtisar

Framework Spring hadir dengan dua container IOC - BeanFactory dan ApplicationContext . The BeanFactory adalah versi yang paling dasar dari kontainer IOC, dan ApplicationContext memperluas fitur BeanFactory .

Dalam tutorial singkat ini, kita akan memahami perbedaan signifikan antara dua wadah IOC ini dengan contoh praktis.

2. Lazy Loading vs.

BeanFactory memuat kacang sesuai permintaan, sementara ApplicationContext memuat semua kacang saat startup . Jadi, BeanFactory lebih ringan dibandingkan dengan ApplicationContext . Mari kita pahami dengan sebuah contoh.

2.1. Pemuatan Malas Dengan BeanFactory

Misalkan kita memiliki kelas kacang tunggal yang disebut Student dengan satu metode:

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

Kami akan mendefinisikan metode postConstruct () sebagai metode init di file konfigurasi BeanFactory kami , ioc-container-difference-example.xml :

Sekarang, mari kita tulis kasus uji yang membuat BeanFactory untuk memeriksa apakah itu memuat kacang Student :

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

Di sini, para mahasiswa objek tidak diinisialisasi . Dengan kata lain, hanya BeanFactory yang diinisialisasi . Kacang didefinisikan dalam kami BeanFactory akan dimuat hanya ketika kita secara eksplisit memanggil getBean () metode .

Mari kita periksa inisialisasi kacang Mahasiswa kita di mana kita secara manual memanggil metode 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()); }

Di sini, kacang Mahasiswa berhasil dimuat. Oleh karena itu, BeanFactory hanya memuat kacang saat dibutuhkan.

2.2. Eager Loading With ApplicationContext

Sekarang, mari gunakan ApplicationContext sebagai pengganti BeanFactory.

Kami hanya akan mendefinisikan ApplicationContext, dan itu akan memuat semua kacang secara instan dengan menggunakan strategi eager-loading:

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

Di sini, objek Student dibuat meskipun kita belum memanggil metode getBean () .

ApplicationContext dianggap sebagai wadah IOC yang berat karena strategi eager-loading-nya memuat semua kacang saat memulai. BeanFactory ringan sebagai perbandingan dan dapat berguna dalam sistem dengan memori terbatas. Namun demikian, kita akan melihat di bagian selanjutnya mengapa ApplicationContext lebih disukai untuk sebagian besar kasus penggunaan .

3. Fitur Aplikasi Perusahaan

ApplicationContext menyempurnakan BeanFactory dalam gaya yang lebih berorientasi kerangka kerja dan menyediakan beberapa fitur yang sesuai untuk aplikasi perusahaan.

Misalnya, ini menyediakan fungsionalitas perpesanan (i18n atau internasionalisasi) , fungsionalitas publikasi acara , injeksi ketergantungan berbasis anotasi , dan integrasi mudah dengan fitur Spring AOP .

Selain itu, ApplicationContext mendukung hampir semua jenis cakupan kacang, tetapi BeanFactory hanya mendukung dua cakupan - Singleton dan Prototipe . Oleh karena itu, sebaiknya gunakan ApplicationContext saat membangun aplikasi perusahaan yang kompleks.

4. Pendaftaran Otomatis BeanFactoryPostProcessor dan BeanPostProcessor

The ApplicationContext otomatis register BeanFactoryPostProcessor dan BeanPostProcessor saat startup. Di sisi lain, BeanFactory tidak mendaftarkan antarmuka ini secara otomatis.

4.1. Pendaftaran di BeanFactory

Untuk memahami, mari kita tulis dua kelas.

Pertama, kami memiliki kelas CustomBeanFactoryPostProcessor , yang mengimplementasikan BeanFactoryPostProcessor :

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

Di sini, kami telah mengganti metode postProcessBeanFactory () untuk memeriksa pendaftarannya.

Kedua, kami memiliki kelas lain, CustomBeanPostProcessor , yang mengimplementasikan 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 }

Di sini, kami telah mengganti metode postProcessBeforeInitialization () untuk memeriksa pendaftarannya.

Selain itu, kami telah mengonfigurasi kedua kelas dalam file konfigurasi ioc-container-difference-example.xml kami :

Mari kita lihat kasus uji untuk memeriksa apakah kedua kelas ini terdaftar secara otomatis selama startup:

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

Seperti yang dapat kita lihat dari pengujian kami, pendaftaran otomatis tidak terjadi .

Sekarang, mari kita lihat kasus uji yang menambahkannya secara manual di 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()); }

Di sini, kami menggunakan metode postProcessBeanFactory () untuk mendaftarkan CustomBeanFactoryPostProcessor dan metode addBeanPostProcessor () untuk mendaftarkan CustomBeanPostProcessor . Keduanya berhasil mendaftar dalam kasus ini.

4.2. Pendaftaran di ApplicationContext

Seperti yang kita catat sebelumnya, ApplicationContext mendaftarkan kedua kelas secara otomatis tanpa menulis kode tambahan.

Mari verifikasi perilaku ini dalam pengujian unit:

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