
Spring中涉及的設計模式總結
實作方式:BeanFactory。Spring中的BeanFactory就是簡單工廠模式的展現,根據傳入一個唯一的辨別來獲得Bean對象,但是否是在傳入參數後建立還是傳入參數前建立這個要根據具體情況來定。
實質:由一個工廠類根據傳入的參數,動态決定應該建立哪一個産品類。
實作原理:
bean容器的啟動階段:
讀取bean的xml配置檔案,将bean元素分别轉換成一個BeanDefinition對象。
然後通過BeanDefinitionRegistry将這些bean注冊到beanFactory中,儲存在它的一個ConcurrentHashMap中。
将BeanDefinition注冊到了beanFactory之後,在這裡Spring為我們提供了一個擴充的切口,允許我們通過實作接口BeanFactoryPostProcessor 在此處來插入我們定義的代碼。典型的例子就是:PropertyPlaceholderConfigurer,我們一般在配置資料庫的dataSource時使用到的占位符的值,就是它注入進去的。
容器中bean的執行個體化階段:
執行個體化階段主要是通過反射或者CGLIB對bean進行執行個體化,在這個階段Spring又給我們暴露了很多的擴充點:
各種的Aware接口,比如 BeanFactoryAware,對于實作了這些Aware接口的bean,在執行個體化bean時Spring會幫我們注入對應的BeanFactory的執行個體。
BeanPostProcessor接口,實作了BeanPostProcessor接口的bean,在執行個體化bean時Spring會幫我們調用接口中的方法。
InitializingBean接口,實作了InitializingBean接口的bean,在執行個體化bean時Spring會幫我們調用接口中的方法。
DisposableBean接口,實作了BeanPostProcessor接口的bean,在該bean死亡時Spring會幫我們調用接口中的方法。
設計意義:
松耦合。可以将原來寫死的依賴,通過Spring這個beanFactory這個工長來注入依賴,也就是說原來隻有依賴方和被依賴方,現在我們引入了第三方——spring這個beanFactory,由它來解決bean之間的依賴問題,達到了松耦合的效果.
bean的額外處理。通過Spring接口的暴露,在執行個體化bean的階段我們可以進行一些額外的處理,這些額外的處理隻需要讓bean實作對應的接口即可,那麼spring就會在bean的生命周期調用我們實作的接口來處理該bean。<code>[非常重要]</code>
實作方式:FactoryBean接口。
實作原理:實作了FactoryBean接口的bean是一類叫做factory的bean。其特點是,spring會在使用getBean()調用獲得該bean時,會自動調用該bean的getObject()方法,是以傳回的不是factory這個bean,而是這個bean.getOjbect()方法的傳回值。
例子:
典型的例子有spring與mybatis的結合。
代碼示例
說明:我們看上面該bean,因為實作了FactoryBean接口,是以傳回的不是 SqlSessionFactoryBean 的執行個體,而是她的 SqlSessionFactoryBean.getObject() 的傳回值。
Spring依賴注入Bean執行個體預設是單例的。
Spring的依賴注入(包括lazy-init方式)都是發生在AbstractBeanFactory的getBean裡。getBean的doGetBean方法調用getSingleton進行bean的建立。
分析getSingleton()方法
getSingleton()過程圖 ps:spring依賴注入時,使用了 雙重判斷加鎖 的單例模式
總結
單例模式定義:保證一個類僅有一個執行個體,并提供一個通路它的全局通路點。
spring對單例的實作:spring中的單例模式完成了後半句話,即提供了全局的通路點BeanFactory。但沒有從構造器級别去控制單例,這是因為spring管理的是任意的java對象。
實作方式:SpringMVC中的擴充卡HandlerAdatper。
實作原理:HandlerAdatper根據Handler規則執行不同的Handler。
實作過程:DispatcherServlet根據HandlerMapping傳回的handler,向HandlerAdatper發起請求,處理Handler。HandlerAdapter根據規則找到對應的Handler并讓其執行,執行完畢後Handler會向HandlerAdapter傳回一個ModelAndView,最後由HandlerAdapter向DispatchServelet傳回一個ModelAndView。
實作意義:HandlerAdatper使得Handler的擴充變得容易,隻需要增加一個新的Handler和一個對應的HandlerAdapter即可。是以Spring定義了一個适配接口,使得每一種Controller有一種對應的擴充卡實作類,讓擴充卡代替controller執行相應的方法。這樣在擴充Controller時,隻需要增加一個擴充卡類就完成了SpringMVC的擴充了。
實作方式:Spring中用到的包裝器模式在類名上有兩種表現:一種是類名中含有Wrapper,另一種是類名中含有Decorator。
實質:
動态地給一個對象添加一些額外的職責。
就增加功能來說,Decorator模式相比生成子類更為靈活。
實作方式:AOP底層,就是動态代理模式的實作。
動态代理:在記憶體中建構的,不需要手動編寫代理類
靜态代理:需要手工編寫代理類,代理類引用被代理對象。
實作原理:切面在應用運作的時刻被織入。一般情況下,在織入切面時,AOP容器會為目标對象建立動态的建立一個代理對象。SpringAOP就是以這種方式織入切面的。 <code>織入:把切面應用到目标對象并建立新的代理對象的過程。</code>
實作方式:spring的事件驅動模型使用的是 觀察者模式 ,Spring中Observer模式常用的地方是listener的實作。
具體實作: <code>事件機制的實作需要三個部分,事件源,事件,事件監聽器</code>
<code>ApplicationEvent抽象類事件</code>
繼承自jdk的EventObject,所有的事件都需要繼承ApplicationEvent,并且通過構造器參數source得到事件源.
該類的實作類ApplicationContextEvent表示ApplicaitonContext的容器事件.
代碼:
ApplicationListener接口事件監聽器
繼承自jdk的EventListener,所有的監聽器都要實作這個接口。
這個接口隻有一個onApplicationEvent()方法,該方法接受一個ApplicationEvent或其子類對象作為參數,在方法體中,可以通過不同對Event類的判斷來進行相應的處理。
當事件觸發時所有的監聽器都會收到消息。
ApplicationContext接口事件源
ApplicationContext是spring中的全局容器,翻譯過來是”應用上下文”。
實作了ApplicationEventPublisher接口。
職責:負責讀取bean的配置文檔,管理bean的加載,維護bean之間的依賴關系,可以說是負責bean的整個生命周期,再通俗一點就是我們平時所說的IOC容器。
ApplicationEventMulticaster抽象類事件源中publishEvent方法需要調用其方法getApplicationEventMulticaster
屬于事件廣播器,它的作用是把Applicationcontext釋出的Event廣播給所有的監聽器.
代碼
實作方式:Spring架構的資源通路Resource接口 。該接口提供了更強的資源通路能力,Spring 架構本身大量使用了 Resource 接口來通路底層資源。
Resource 接口介紹
source 接口是具體資源通路政策的抽象,也是所有資源通路類所實作的接口。
Resource 接口主要提供了如下幾個方法:
getInputStream():定位并打開資源,傳回資源對應的輸入流。每次調用都傳回新的輸入流。調用者必須負責關閉輸入流。
exists():傳回 Resource 所指向的資源是否存在。
isOpen():傳回資源檔案是否打開,如果資源檔案不能多次讀取,每次讀取結束應該顯式關閉,以防止資源洩漏。
getDescription():傳回資源的描述資訊,通常用于資源處理出錯時輸出該資訊,通常是全限定檔案名或實際 URL。
getFile:傳回資源對應的 File 對象。
getURL:傳回資源對應的 URL 對象。 <code>最後兩個方法通常無須使用,僅在通過簡單方式通路無法實作時,Resource 提供傳統的資源通路的功能。</code>
Resource 接口本身沒有提供通路任何底層資源的實作邏輯,針對不同的底層資源,Spring 将會提供不同的 Resource 實作類,不同的實作類負責不同的資源通路邏輯。
Spring 為 Resource 接口提供了如下實作類:
UrlResource:通路網絡資源的實作類。
ClassPathResource:通路類加載路徑裡資源的實作類。
FileSystemResource:通路檔案系統裡資源的實作類。
ServletContextResource:通路相對于 ServletContext 路徑裡的資源的實作類.
InputStreamResource:通路輸入流資源的實作類。
ByteArrayResource:通路位元組數組資源的實作類。 <code>這些 Resource 實作類,針對不同的的底層資源,提供了相應的資源通路邏輯,并提供便捷的包裝,以利于用戶端程式的資源通路。</code>
經典模闆方法定義:
父類定義了骨架(調用哪些方法及順序),某些特定方法由子類實作
最大的好處:代碼複用,減少重複代碼。除了子類要實作的特定方法,其他方法及方法調用順序都在父類中預先寫好了。
是以父類模闆方法中有兩類方法:
共同的方法:所有子類都會用到的代碼
不同的方法:子類要覆寫的方法,分為兩種:
抽象方法:父類中的是抽象方法,子類必須覆寫
鈎子方法:父類中是一個空方法,子類繼承了預設也是空的 <code>注:為什麼叫鈎子,子類可以通過這個鈎子(方法),控制父類,因為這個鈎子實際是父類的方法(空方法)!</code>
Spring模闆方法模式實質: <code>是模闆方法模式和回調模式的結合</code>,是Template Method不需要繼承的另一種實作方式。Spring幾乎所有的外接擴充都采用這種模式。
具體實作:JDBC的抽象和對Hibernate的內建,都采用了一種理念或者處理方式,那就是模闆方法模式與相應的Callback接口相結合。
采用模闆方法模式是為了以一種統一而集中的方式來處理資源的擷取和釋放,以JdbcTempalte為例:
引入回調原因:
JdbcTemplate是抽象類,不能夠獨立使用,我們每次進行資料通路的時候都要給出一個相應的子類實作,這樣肯定不友善,是以就引入了回調 。
回調代碼
利用回調方法重寫JdbcTemplate方法
Jdbc使用方法如下:
為什麼JdbcTemplate沒有使用繼承?因為這個類的方法太多,但是我們還是想用到JdbcTemplate已有的穩定的、公用的資料庫連接配接,那麼我們怎麼辦呢?我們可以把變化的東西抽出來作為一個參數傳入JdbcTemplate的方法中。但是變化的東西是一段代碼,而且這段代碼會用到JdbcTemplate中的變量。怎麼辦?那我們就用回調對象吧。在這個回調對象中定義一個操縱JdbcTemplate中變量的方法,我們去實作這個方法,就把變化的東西集中到這裡了。然後我們再傳入這個回調對象到JdbcTemplate,進而完成了調用。
參考:https://www.cnblogs.com/digdeep/p/4518571.html https://www.cnblogs.com/tongkey/p/7919401.html https://www.cnblogs.com/fingerboy/p/6393644.html https://blog.csdn.net/ovoo_8/article/details/51189401 https://blog.csdn.net/z69183787/article/details/65628166