Di kelas Java, seorang pria hebat bernama Rod Johnson menemukan bahwa pengembangan tingkat perusahaan Java awal berada dalam keadaan kacau.
Jadi diputuskan untuk menulis infrastruktur umum yang dapat menyelesaikan masalah.
Karena sangat percaya bahwa pemrograman yang berorientasi antarmuka dapat meminimalkan perubahan, tetapi juga memfasilitasi ekspansi dan perubahan. Jadi, itu menulis antarmuka berikut.
Hal pertama yang dibuat dalam keadaan kacau adalah ibu dari semua objek, beanfactory, dan dengan itu, Anda dapat memperoleh semua objek dan atribut yang dipelihara, yaitu, pertama -tama, Gaia - Bunda Bumi.
Dengan Mother Beanfactory asli, pikir Johnson, bagaimana jika saya ingin mendapatkan satu set benda kacang, bukan hanya satu atau beberapa? Selain itu, bagaimana jika anak ibu juga ingin melahirkan pasangan? Oleh karena itu, Johnson membuat ListableAnfactory untuk mengoperasikan satu set objek kacang. Misalnya, GetBeansOfType dapat memperoleh satu set kacang dengan jenis yang sama berdasarkan itu; menciptakan HierarchicalBeanFactory untuk menyelesaikan masalah hierarkis dari beberapa beanfactory, seperti GetParentBeanFactory dapat memperoleh pabrik induk dari beanfactory.
BeanFactory ini pada akhirnya digunakan pada suatu aplikasi, sehingga beanfactory perlu diberikan kemampuan untuk bergerak dalam suatu aplikasi. Dalam beanfactory, Anda hanya perlu mempertimbangkan perilaku yang terkait dengan kacang, seperti cara mendapatkan kacang, jenis kacang, dll.; Dan jika Anda ingin memberi mereka kemampuan dalam aplikasi, Anda perlu mempertimbangkan lebih banyak, seperti nama aplikasi, waktu startup, ID, dll. Perilaku dan atribut yang terkait dengan aplikasi itu sendiri, jadi Johnson berpikir untuk membuat ApplicationContext. Johnson berpikir bahwa ApplicationContext ini harus dapat melakukan banyak hal, dan harus dapat menangani informasi teks yang diparameterisasi dan terinternasionalisasi, sehingga menambahkan antarmuka PesanSource; Itu harus dapat menerbitkan acara untuk memisahkan komponen, sehingga memiliki antarmuka ApplicationEventPublisher; Itu harus dapat memperoleh file sumber daya, sehingga memiliki antarmuka ResourcePatternResolver; Itu harus dapat memiliki objek pemrosesan yang berbeda di lingkungan yang berbeda, sehingga memiliki antarmuka yang dapat dibatalkan lingkungan.
ApplicationContext mewarisi semua antarmuka ini.
Tetapi yang paling penting adalah bahwa baik BeanFactory dan ApplicationContext perlu memiliki kemampuan yang dapat dikonfigurasi, sehingga ada sub-interaksi yang dapat dikonfigurasibeli dan ConfigurableApplicationContext; Selain itu, Web adalah tren yang sangat penting pada waktu itu, dan itu agak unik dibandingkan dengan aplikasi lain, jadi perlu mendapatkan ServletContext, jadi ada WebApplicationContext.
Sejauh ini, Johnson telah berpikir abstrak tentang perilaku antarmuka dan belum mengimplementasikannya secara rinci.
Melihat Beanfactory dan ApplicationContext yang dibuat, Johnson menyadari bahwa pekerjaan hari itu masih jauh dari selesai karena tidak ada solusi nyata untuk bagaimana membuat seluruh sistem bekerja, jadi Johnson mulai berpikir tentang bagaimana menerapkannya.
Hal pertama yang dipikirkan Johoson adalah kemampuan apa yang harus dimiliki oleh implementasi ini? Tentu saja, kita perlu menyertakan AutoWireCapableBeanFactory, ListableBeanFactory dan ConfigableArbeanFactory yang disebutkan sebelumnya. Oleh karena itu, ConfigurableListableBeanFactory dibuat. Kedua, beberapa kemampuan untuk benda kacang perlu dipertimbangkan, satu adalah kemampuan untuk alias; Yang kedua adalah kemampuan untuk menyimpan objek singleton; Yang ketiga adalah kemampuan untuk cache; Mereka diimplementasikan di kelas SimplealiSregistry, kelas defaultingonBeanRegistry dan kelas dukungan pabrik masing -masing.
Akhirnya, DefaultListableBeanFactory diciptakan, yang merupakan prototipe semua pabrik IOC di musim semi dan merupakan anak nyata pertama beanfactory. Anak ini sangat penting dan telah menjadi dasar untuk penciptaan independen wadah IOC. Jika diperluas dan digunakan, kebanyakan dari mereka diwarisi atau digunakan dalam kombinasi.
Jika Anda ingin menginisialisasi DefaultListableBeanFactory, Anda dapat menggunakan kode berikut
ClassPathResource res = new ClassPathResource ("ApplicationContext.xml"); DefaultListableBeanFactory f = New DefaultListableBeanFactory (); XmlbeandefinitionReader r = xmlbeandefinitionReader baru (f); R.LoadBeandefinitions (res); Selanjutnya, Johnson berpikir bahwa BeanFactory memiliki implementasi default yang relatif komprehensif, jadi bagaimana dengan ApplicationContext? Jadi Johnson tanpa lelah membuat tiga implementasi ApplicationContext yang penting: FileSyStemXMLapPlicationContext, ClassPathXMLapPlicationContext, AnnotationConfigWebApplicationContext (Faktanya, ada banyak lagi, seperti menangani portlet dan menangani web)
Hal pertama yang dipertimbangkan Johnson adalah bagaimana melakukan proses startup musim semi. Itu harus ditempatkan dalam level yang relatif abstrak sehingga semua kelas di level bawah dapat digunakan kembali. Jadi dia mengimplementasikan ConfigurableApplicationContext menggunakan AbstractApplicationContext. Ada juga fungsi yang sangat penting, yaitu memuat file dalam bentuk sumber daya, yang memerlukan abstrak sumber daya ke dalam kelas sumber daya dan mengabstraksi implementasi spesifik dari sumber daya penentuan posisi ke sumber daya. AbstractApplicationContext juga perlu mewarisi defaultresourceloader untuk menyediakan fungsi ini. AbstractApplicationContext menyelesaikan seluruh proses startup (Tuhan mengaturnya untuk diselesaikan pada hari berikutnya), tetapi tidak mengelola beanfactory. Jadi, subclass abstractrefreshableApplicationContext melakukan ini secara khusus, menerapkan refreshbeanFactory, closeBeanFactory, getBeanFactory secara khusus mengelola siklus hidup beanfactory, tetapi abstraktrefreshableApplicationContext masih tidak memuat semua bean yang dikonfigurasi. Tempat memuat sumber daya yang dikonfigurasi, itu benar -benar menuju ke subkelas bawah untuk melakukannya, seperti fileSySyStemXmlapplicationContext, yaitu membaca XML ApplicationContext ke sistem file; ClassPathXMLapPlicationContext adalah untuk membaca aplikasi ini untuk jalur pemuatan kelas. AnnotationConfigWebApplicationContext memuat kacang dari anotasi file kelas, dan pemindaian musim semi dimulai dari sekarang.
Melihat bahwa kerangka utama telah ditetapkan, Johnson tertidur dengan puas dengan senyuman.
Hari pertama, Johnson menyelesaikan kerangka kerja keseluruhan musim semi.
Pada hari kedua, Johnson sedang bersiap untuk benar -benar menangani masalah sebelumnya. Misalnya, proses inisialisasi container pegas. Seperti yang ditunjukkan pada gambar, Johnson membagi proses ini menjadi banyak subproses, yang semuanya bekerja di sekitar tujuan besar memuat kacang.
Proses ini ditempatkan dalam metode refresh di AbstractApplicationContext. Kode ini adalah sebagai berikut: Johnson membagi proses penyegaran menjadi banyak subproses, dan subproses ini berada pada tingkat abstrak yang sama. Cara menulis ini adalah memberi generasi masa depan panutan.
public void refresh () melempar BeansException, IllegalStateException {disinkronkan (this.startupshutDownMonitor) {// Siapkan konteks ini untuk menyegarkan. preparerefresh (); // Beri tahu subkelas untuk menyegarkan pabrik kacang internal. ConfigurableListableBeanFactory beanFactory = ort praFreshBeanFactory (); // Siapkan pabrik kacang untuk digunakan dalam konteks ini. Persiapan Persiapan (Beanfactory); Coba {// Memungkinkan pasca pemrosesan pabrik kacang dalam subkelas konteks. PostprocessBeanFactory (BeanFactory); // Invoke Processorsorsor Pabrik terdaftar sebagai kacang dalam konteks. InvokeBeanFactoryPostProcessors (BeanFactory); // Daftarkan prosesor kacang yang mencegat penciptaan kacang. RegisterBeanPostProcessors (BeanFactory); // inisialisasi sumber pesan untuk konteks ini. initmessageSource (); // inisialisasi multicaster acara untuk konteks ini. InitApplicationEventMulticaster (); // Inisialisasi kacang khusus lainnya dalam subkelas konteks tertentu. onrefresh (); // Periksa kacang pendengar dan daftarkannya. RegisterListeners (); // Instantiate semua singleton yang tersisa (non-lazy-init). finishbeanfactoryInitialisasi (beanfactory); // Langkah Terakhir: Publikasikan acara yang sesuai. finishrefresh (); } catch (BeansException ex) {// Hancurkan Singleton yang Sudah Dibuat untuk Menghindari Sumber Daya Bergantung. DestroyBeans (); // Reset bendera 'aktif'. CancelRefresh (EX); // Perpanjakan pengecualian untuk penelepon. lempar ex; }}} Jika Anda melihatnya pada tingkat yang lebih tinggi, proses -proses ini sebenarnya berputar di sekitar beberapa aspek: 1. Segarkan siklus hidup; 2. Inisialisasi dan persiapan beanfactory; 3. Hasilkan dan Daftarkan Beandefinition; 4. Post Processor Beanfactory; 5. Atur pesan, acara, dan pendengar.
1. Siklus hidup yang menyegarkan
Persiapan, proses ini terutama mencatat log dan menunjukkan bahwa Spring telah dimulai, menginisialisasi sumber daya properti (seperti menginisialisasi beberapa sumber daya di Serlvet), dan memverifikasi sumber daya properti (seperti hanya menulis kunci tanpa nilai).
Onrefresh, tujuannya adalah untuk memberikan beberapa konteks aplikasi khusus, sehingga mereka dapat berkembang selama proses penyegaran. Sebagian besar penggunaan saat ini adalah mengatur tema untuk konteks aplikasi servlet
finishrefresh, lakukan beberapa pekerjaan finishing, seperti menginisialisasi siklus hidup, acara penerbitan yang berakhir untuk penyegaran, dll.
CancelRefresh, terutama mengubah keadaan saat ini menjadi non-aktif ketika pengecualian terjadi.
2. Inisialisasi dan Persiapan Beanfactory
Johnson berpikir bahwa kita harus membiarkan beanfactory memuat dan mendaftarkan kacang secara transparan ketika diinisialisasi, jadi enkapsulasi saya sangat sukses untuk dunia luar, jadi langkah ini sebenarnya melakukan banyak hal. Angka berikut menghilangkan banyak langkah dan hanya mencantumkan poin -poin penting.
AbstractApplicationContext akan memanggil RefreshBeanFactory. Ini pertama -tama akan memeriksa dan menutup beanfactory yang ada, kemudian membuat beanfactory baru, dan kemudian menggunakan pabrik ini untuk memuat semua seefinisi beand.
Di antara mereka, loadBeandefinitions akan diserahkan kepada subkelas untuk implementasi yang berbeda. Misalnya, AbstractXMLapPlicationContext terutama dibaca melalui XML; AnnotationConfigWapplicationContext Implementasi akan menghubungi pemindai untuk memindai kacang di kelas.
3. Hasilkan dan Daftarkan Beandefinition
Setelah mem -parsing konfigurasi XML, metode parsedefaultElement dari defaultBeandefinitionDocumentReader akan melakukan pemrosesan yang sesuai berdasarkan elemen dalam XML. Di antara mereka, ketika menemukan elemen kacang, metode registerbeandefinition di BeandefinitionReaderutils akhirnya akan dipanggil. Parameter yang disahkan dalam metode ini adalah Beandefinitionregistry, yang sebenarnya memanggil kembali metode registerBeandefinition dari defaultListableBeanFactory untuk mendaftarkan beandefinition (defaultListableBeanFactory mengimplementasikan beandefinitionregistry).
4. Post Processor Beanfactory
Postprocessor beanfactory adalah cara yang disediakan oleh Spring untuk memungkinkan subclass -nya fleksibel. Ada 2 langkah di musim semi: postprocessbeanfactory, invokeBeanFactoryPostProcesors. RegisterBeanPostProcessors Instantiate dan hubungi semua beanpostprocessors, yang digunakan untuk memperluas kacang sebelum dan sesudah inisialisasi kacang.
5. Mengatur pesan, acara, dan pendengar
Atur sumber pesan default ke DelegatingMessageSource. Jika sudah ada sumber pesan di pabrik, gunakan sumber pesan ini. Acara multicaster adalah SimpleApplicationEventMulticaster. Jika sudah ada ApplicationEventMulticaster di pabrik, gunakan ApplicationEventMulticaster ini dan daftarkan semua pendengar aplikasi untuk menerima acara.
PesanSource adalah metode penting untuk file sumber daya internasional. Spring mendukung sumber pesan di ApplicationContext.
Spring menyediakan implementasi default dari pesan sumber, menggunakan java.util.resourceBundle untuk mengekstrak pesan. Spring dapat secara langsung mengakses pesan dari ApplicationContext.GetMessage () dengan mengonfigurasi kacang dengan ID khusus sebagai pesan pesan dan mengatur nama file i18n. Jika di JSP, Anda juga dapat mengakses pesan melalui tag pesan: Pesan.
Acara: Acara adalah mekanisme decoupling yang relatif penting. Spring telah memperkenalkannya di Core ApplicationContext. Prinsipnya relatif sederhana. Di satu sisi, generator acara dapat mengirim acara; Di sisi lain, tampaknya pendengar acara dapat menanggapi acara. Implementasi spesifik pada dasarnya memiliki koleksi pendengar acara di generator dan "Daftar" (yaitu, bergabunglah) semua pendengar untuk koleksi pendengar acara ini.
Di Spring, ApplicationContext digunakan sebagai generator acara, ApplicationListeners digunakan sebagai koleksi pendengar, dan ApplicationEventMulticaster digunakan untuk menerbitkan acara.
Beberapa langkah untuk mempublikasikan suatu acara:
Langganan: Awalnya AddApplicationListener ke koleksi pendengar.
PUBLISH: ApplicationContext mewarisi ApplicationEventPublisher, sehingga menerapkan PublishEvent. Metode ini pertama -tama akan melintasi koleksi ApplicationListeners dari ApplicationContext ini, hubungi OnApplicationEvent untuk setiap pendengar, sehingga setiap pendengar akan diberitahu; Setelah langkah ini selesai, acara yang sama akan diterbitkan untuk semua ApplicationListeners dari ApplicationContext Parent.
Penerbitan acara sangat umum. Aplikasi kami sendiri tidak hanya dapat menggunakan penerbitan acara ini, tetapi kerangka kerja Spring itu sendiri juga menggunakan penerbitan acara. Berikut adalah beberapa aplikasi acara di musim semi:
ContextrefreshedEvent akan diterbitkan di finishrefresh untuk menunjukkan bahwa penyegaran berakhir dan memberi tahu pendengar. Di ApplicationContext, metode start and stop akan menerbitkan acara yang menunjukkan konteks awal atau akhir.
Setelah Johnson menciptakan kerangka kerja utama dan proses operasi musim semi, ia menemukan bahwa Spring menyediakan banyak tempat ekspansi yang fleksibel. Jadi Johnson sedang bersiap untuk mengumumkan penggunaan ekspansi yang fleksibel ini pada hari ketiga.
1. Beanpostprocessor. BeanPostProcessor menyediakan antarmuka ekstensi setelah penciptaan kacang selesai. Ketika Anda perlu melakukan beberapa pemrosesan pada kacang setelah dibuat, beanpostprocessor adalah metode yang disukai.
2. Sadar. Kacang yang disuntikkan perlu mengetahui beberapa bagian dari wadahnya. Spring menyelesaikan panggilan balik melalui Sadar, seperti BeanNeMeaware, yang memungkinkan kacang mengetahui namanya. BeanfactoryAware dapat membiarkan kacang memahami BeanFactory, ApplicationContextAware, yang memungkinkan kacang mengoperasikan ApplicationContext. Dengan cara ini, kacang yang disuntikkan dengan musim semi dapat melakukan berbagai hal.
Untuk perpanjangan beanpostprocessor, Spring sendiri memiliki contoh bagaimana mengidentifikasi kacang yang sadar. Kacang yang sadar adalah kacang yang relatif istimewa, dan musim semi membutuhkan beberapa atribut tambahan untuk itu. Jadi bagaimana musim semi akan digunakan untuk proses injeksi? Faktanya, Spring tidak menulisnya dalam proses pemrosesan inti, tetapi memasukkannya ke ApplicationContextAwareProcessor, BeanpostProcessor, dan akhirnya InvokeAwareInterfaces untuk menentukan jenis kacang dan menyuntikkan atribut yang sesuai. Pendekatan ini menggunakan beanpostprocessor untuk menyelesaikan penggunaan lain yang diperpanjang, yang benar -benar luar biasa.
Private void InvokeAwareInterFaces (Object Bean) {if (bean instanceof sadar) {if (instance bean dari lingkungan lingkungan) {((lingkungan) bean) .setenvironment (this.applicationContext.getEnvironment ()); } if (bean instance dari embeddedvalueresolverAware) {((embeddedvalueResolverAware) bean) .setembeddedvalueResolver (embeddeddedvalueResolver (this.ApplicationContext.getBeanFactory ())); } if (bean instance dari resourceloaderAware) {((resourceloaderAware) bean) .setResourceloader (this.applicationContext); } if (bean instance dari ApplicationEventPublisherAware) {((ApplicationEventPublisherAware) bean) .setApplicationEventPublisher (this.applicationContext); } if (bean instance dari pesan sumber daya) {((pesan sumber daya) bean) .setMessageSource (this.applicationContext); } if (bean instanceof applicationContextAware) {((applicationContextAware) bean) .setApplicationContext (this.applicationContext); }}}Ada lebih banyak aturan untuk menggunakan sadar. Misalnya, kode berikut dapat memahami ApplicationContext. Setelah Spring membuat kacang ini, ia akan menyuntikkan ApplicationContext, sehingga kami dapat menggunakan konteks ini untuk menyelesaikan penerbitan acara.
kelas publik HelloBean mengimplementasikan applicationContextAware {private applicationContext applicationContext; string pribadi helloword = "Halo! Dunia!"; public void setApplicationContext (ApplicationContext Context) {this.applicationContext = konteks; } public void setHelloword (string helloword) {this.helloword = helloword; } public string getHelloword () {applicationContext.publishevent (properti baruGettedEvent ("[" + helloword + "] adalah gotted")); Kembalikan Helloword; }} 3. BeanFactoryPostProcessor, postprocessor ini biasanya digunakan untuk menangani antarmuka yang diperluas yang dibuat oleh BeanFactory. Contohnya adalah sebagai berikut. Setelah menyuntikkan kacang ini, ia akan secara otomatis mencetak jumlah kacang yang disuntikkan setelah kreasi beanfactory:
Kelas Publik Beancounter mengimplementasikan BeanFactoryPostProcessor {@Override public void postprocessBeanFactory (configurableListableBeanFactory beanfactory) melempar beansexception {system.out.println (beanfactory.getbeNDefinitioncount ()); }} 4. FactoryBean. FactoryBean adalah kacang khusus, yang memungkinkan injeksi ke dalam wadah musim semi dan menghasilkan kacang asli, sehingga dapat didefinisikan dengan cara ini. FactoryBean sendiri adalah kacang, yang memiliki kemampuan untuk menyediakan kacang. Berikut ini dimulai dengan panggilan pabrik dan berbicara tentang bagaimana Spring menggunakan kacang ini.
Untuk membedakan antara kacang biasa dan pabrik, musim semi juga harus memiliki proses menilai dan menanganinya secara khusus. Proses ini ada di GetObjectForBeanStance of AbstractBeanFactory
Objek yang dilindungi getObjectForBeanInstance (objek beanInstance, nama string, string beanname, rootbeandefinition mbd) {// Jangan biarkan kode panggilan mencoba untuk mendereferensi pabrik jika kacang bukan pabrik. if (beanfactoryutils.isfactorydereference (name) &&! (BeanInstance instance dari factorybean)) {lempar beanisnotafactoryException baru (transformedbeanname (name), beaninstance.getclass ()); } // Sekarang kita memiliki instance kacang, yang mungkin kacang normal atau pabrik. // Jika itu adalah pabrik, kami menggunakannya untuk membuat instance kacang, kecuali jika // penelepon benar -benar menginginkan referensi ke pabrik. if (! (Contoh beanInstance dari pabrik) || beanfactoryutils.isfactorydereference (name)) {return beanInstance; } Objek objek = null; if (mbd == null) {objek = getCachedObjectForFactoryBean (beanname); } if (object == null) {// return bean instance dari pabrik. Factorybean <?> factory = (factorybean <?>) Beaninstance; // cache objek yang diperoleh dari pabrik jika itu adalah singleton. if (mbd == null && containsbeandefinition (beanname)) {mbd = getmergedlocalbeandefinition (beanname); } boolean sintetis = (mbd! = null && mbd.issynthetic ()); objek = getObjectFromFactoryBean (pabrik, beanname ,! sintetis); } return objek; } Dapat dilihat bahwa jika itu adalah kacang biasa, itu akan dikembalikan secara langsung, dan jika itu adalah pabrik, panggilan terakhir akan menghubungi pabrik. GetObject untuk mengembalikan objek tertentu. Jika Anda menganggap seluruh musim semi sebagai pabrik abstrak dan ketika memproduksi kacang abstrak, pabrik adalah pabrik spesifik yang menghasilkan objek yang Anda butuhkan.
Ada banyak penggunaan pabrik di musim semi. Untuk memberikan contoh yang relatif umum, ketika mengintegrasikan Sesi Sesi Hibernate, LocalSessionFactoryBean biasanya disuntikkan, tetapi sesi ini sebenarnya bukan kacang biasa. Ini dapat diproduksi hanya dengan menyuntikkannya ke dalam file konfigurasi. Ini memiliki banyak bagian yang disesuaikan, jadi Spring membuat kacang ini menjadi pabrik dan mengendalikan objek produksinya.