作者:寧愿
juejin.im/post/5c11b1e06fb9a04a0d56b787
導語
Spring是一個分層的JAVASE/EE full-stack(一站式) 輕量級開源框架。也是幾乎所有Java工作者必須要掌握的框架之一,其優(yōu)秀的設(shè)計思想以及其代碼實現(xiàn)上的藝術(shù)也是我們需要掌握的。
要學習Spring,除了在我們的項目中使用之外,也需要對它的源碼進行研讀,但是Spring的實現(xiàn)涵蓋的知識很多,在加上其中的類的數(shù)量也是非常的多,在我們閱讀源碼時可能會在幾十個類之間穿插閱讀,很有可能一不小心就導致思維混亂。
有鑒于此,我這里先對Spring中的幾個重要的模塊進行一個手動的簡易實現(xiàn),一是熟悉這些模塊的原理,同時也是仿造Spring中的結(jié)構(gòu)來對后面閱讀源碼打下基礎(chǔ)。
IOC(Inversion of Control)
Inversion of Control即控制反轉(zhuǎn),其意思是將我們之前由客戶端代碼來創(chuàng)建的對象交由IOC容器來進行控制,對象的創(chuàng)建,初始化以及后面的管理都由IOC完成。
IOC的好處
解耦:IOC的出現(xiàn)解決了類與類之間的耦合,我們在Web開發(fā)的Servlet時代,如果一個Servlet需要依賴另一個類的某些實現(xiàn),那么我們需要在當前類對依賴的類進行創(chuàng)建和初始化,如果其他類也依賴了這個類,那也需要進行創(chuàng)建和初始化,而交給了IOC來管理的話,那么在需要的時候只需向IOC進行申請,而不需要重復的創(chuàng)建和初始化。當然,IOC也允許每次都重新創(chuàng)建一個新的對象。
方便與AOP進行配合:AOP也是一個使用十分頻繁的功能,通過IOC可以十分方便的與AOP進行配合。
IOC中設(shè)計的設(shè)計模式
工廠模式。IOC容器來負責創(chuàng)建管理類實例對象,在需要時向IOC進行申請,從IOC中獲取。所以IOC容器也稱為bean工廠。
工廠模式是一種比較簡單易懂的設(shè)計模式,這里就不在介紹了,如果有需要的可以看看工廠模式。
IOC的手動實現(xiàn)
Bean定義
IOC的主要的功能便是對Bean進行管理,包括創(chuàng)建、初始化、管理以及銷毀的工作。首先我們面對的問題就是我們怎么讓IOC能夠創(chuàng)建一個Bean?為了創(chuàng)建Bean我們需要提供一些什么?
如何創(chuàng)建Bean
在不手動通過new關(guān)鍵字創(chuàng)建的情況下創(chuàng)建類實例的對象方法有兩種:
- 反射:通過反射的方法可以創(chuàng)建類的實例:clazz.getClass().newInstance();。
- 工廠模式:工廠模式可以讓我們在不接觸實例類的情況下創(chuàng)建出實例。
publicclassPersonFactory{publicPersongetPerson(){returnnewPerson();}}
為了創(chuàng)建Bean我們需要提供什么
通過分析上面的兩種方法可以輕松得出答案。
對于反射的方式我們僅需提供實例的Class對象。
對于工廠方法我們需要提供的就是創(chuàng)建該類的工廠名(factoryName)和方法名(methodName);
除了創(chuàng)建bean還需要做些什么
IOC容器是對bean的整個生命周期進行管理,除了創(chuàng)建之外還需要對bean進行初始化,以及不需要時對bean進行銷毀的工作(如釋放資源等)。所以我們還需要提供初始化和銷毀等操作。
到這里創(chuàng)建bean需要的基本分析完了,看類圖:
Bean工廠
Bean的定義解決了,但是這個bean定義以及創(chuàng)建好的Bean實例放在哪里呢,我們需要一個統(tǒng)一的地方來存放這些東西以方便我們要用的時候方便取。
我們定義一個Bean工廠來存放bean,在需要的時候從bean工廠中取即可,bean工廠對外提供的也僅僅是一個獲取bean的方法即可,由于bean的類型不定,所以返回值定位Object。
注冊Bean定義
到了現(xiàn)在我們有了創(chuàng)建bean的Bean定義,有了存放和管理bean的Bean工廠,現(xiàn)在需要考慮的是怎么來聯(lián)系這兩個類,我們還需要另外一個接口,接口的功能是讓我們能注冊和獲取bean定義,這里我們通過beanName來區(qū)分不同的bean。
代碼實現(xiàn)
到這里我們實現(xiàn)一個簡易的IOC容器的需要的東西基本準備完成了,看下基本類圖:
基本代碼實現(xiàn):
DefaultBeanDefinition:
publicclassDefaultBeanDefinitionimplementsBeanDefinition{privateClass<?>clazz;privateStringbeanFactoryName;privateStringcreateBeanMethodName;privateStringstaticCreateBeanMethodName;privateStringbeanInitMethodName;privateStringbeanDestoryMethodName;privatebooleanisSingleton;//setterpublicvoidsetSingleton(booleansingleton){isSingleton=singleton;}@OverridepublicClass<?>getBeanClass(){returnthis.clazz;}@OverridepublicStringgetBeanFactory(){returnthis.beanFactoryName;}@OverridepublicStringgetCreateBeanMethod(){returnthis.createBeanMethodName;}@OverridepublicStringgetStaticCreateBeanMethod(){returnthis.staticCreateBeanMethodName;}@OverridepublicStringgetBeanInitMethodName(){returnthis.beanInitMethodName;}@OverridepublicStringgetBeanDestoryMethodName(){returnthis.beanDestoryMethodName;}@OverridepublicStringgetScope(){returnthis.isSingleton?BeanDefinition.SINGLETION:BeanDefinition.PROTOTYPE;}@OverridepublicbooleanisSingleton(){returnthis.isSingleton;}@OverridepublicbooleanisPrototype(){return!this.isSingleton;}}
DefaultBeanFactory:
簡單測試一下:實例bean:
publicclassUser{privateStringname;privateintage;//gettersetterpublicvoidinit(){System.out.println("init...");}publicvoiddestory(){System.out.println("destory...");}}
工廠類:
publicclassTestFactory{publicObjectcreateMethod(){returnnewUser();}publicstaticObjectstaticCreateMethod(){returnnewUser();}}
測試類:
小結(jié)
一個簡易的容器就這樣實現(xiàn)了,當然我們這里只是具備了基本的功能,實際上還差的遠,比如帶參數(shù)的bean的實例化等功能。但是IOC的基本原理已經(jīng)表達出來了,后面我們只需在這個基礎(chǔ)上添加新的功能即可。