Spring源碼(七)-IOC中的那些設計模式

前言

接上一篇講下spring-ioc中的設計模式。Spring作為一款及其優(yōu)秀的框架,其代碼的編寫非常優(yōu)秀,里面采用了大量的設計模式。下面我們一點點分析。
先簡單說下常見的設計模式

  • 1、工廠模式
  • 2、單例模式
  • 3、策略模式
  • 4、裝飾器模式

參考:設計模式學習

1、工廠模式

【參考】:工廠模式的區(qū)別

1.1、定義

工廠模式可將Java對象的調用者從被調用者的實現邏輯中分離出來,調用者只需關心被調用者必須滿足的規(guī)則(接口),而不必關心實例的具體實現過程。工廠模式由抽象產品(接口)、具體產品(實現類)、生產者(工廠類)三種角色組成。

1.2、Spring中工廠模式的應用

Spring中在各種BeanFactory以及ApplicationContext創(chuàng)建中都用到了典型的工廠方法模式。ApplicationContext的設計圖如下,SpringBean的體系結構比較復雜,頂級接口是BeanFactory;BeanFactory共有三個子接口:ListableBeanFactory、HierarchicalBeanFactory和AutowireCapableBeanFactory,還有一個SimpleJndiBeanFactory實現類。這三個子接口集成了頂級接口并對BeanFactory的功能進行了增強,稱為二級接口;ConfigurableBeanFactory對二級接口HierarchicalBeanFactory進行了再次增強,它還繼承了另一個外來的接口SingletonBeanRegistry,可以被稱為三級接口;ConfigurableListableBeanFactory是一個更強大的接口,繼承了上述的所有接口,稱為四級接口。其余的為抽象類,實現了Spring Bean四級接口所定義的所有功能。

2、單例模式

【參考】: 單例

2.1、定義

單例模式具有以下特點:

  • 1、單例類只能有一個實例。
  • 2、單例類必須自己創(chuàng)建自己的唯一實例。
  • 3、單例類必須給所有其他對象提供這一實例

2.2 Spring中單例模式的使用

在Spring中,所有的bean默認都是單例創(chuàng)建的。在創(chuàng)建bean的代碼中我們經??吹絊ingleton這個單詞。下面我們通過代碼看看單例是怎么實現的。

【AbstractBeanFactory】
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
            @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
·············           
        //實例化依賴的bean之后可以實例化mbd本身了
        //單例模式的創(chuàng)建
        if (mbd.isSingleton()) {
            sharedInstance = getSingleton(beanName, () -> {
                try {
                    /**
                     *核心創(chuàng)建bean
                     */
                    return createBean(beanName, mbd, args);
                }
                catch (BeansException ex) {
                    // Explicitly remove instance from singleton cache: It might have been put there
                    // eagerly by the creation process, to allow for circular reference resolution.
                    // Also remove any beans that received a temporary reference to the bean.
                    destroySingleton(beanName);
                    throw ex;
                }
            });
            //真正的bean初始化處理
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
        }
···········             
}       

通過將工廠函數傳入getSingleton函數中,就可以獲得一個Bean單例。單例的生成是通過修改createBean函數的參數實現的,其中mbd是一個RootBeanDefinition類,它存儲了生成Bean實例所需要的信息。在createBean之中的代碼里,程序調用實例化Bean的函數initializeBean

3、策略模式

【參考】:策略模式

3.1 定義

在策略模式(Strategy Pattern)中,一個類的行為或其算法可以在運行時更改。這種類型的設計模式屬于行為型模式。在策略模式中,我們創(chuàng)建表示各種策略的對象和一個行為隨著策略對象改變而改變的 context 對象。策略對象改變 context 對象的執(zhí)行算法。策略模式實際就是一堆算法族的封裝。

3.2 Spring中策略模式的應用

當bean需要訪問資源配置文件時,Spring有兩種方式

  • 代碼中獲取Rescource實例
  • 依賴注入
    第一種方式需要獲取rescource資源的位置,代碼中耦合性太高,而今我們一直使用注解,依賴注入的方式去獲取。這樣的話就無需修改程序,只改配置文件即可。
<beans> 
   <bean id="test" class="com.example.Test"> 
   <!-- 注入資源 --> 
      <property name="tmp" value="classpath:book.xml"/>
   </bean> 
</beans>

在依賴注入的過程中,Spring會調用ApplicationContext 來獲取Resource的實例。然而,Resource 接口封裝了各種可能的資源類型,包括了:UrlResource,ClassPathResource,FileSystemResource等,Spring需要針對不同的資源采取不同的訪問策略。在這里,Spring讓ApplicationContext成為了資源訪問策略的“決策者”。在資源訪問策略的選擇上,Spring采用了策略模式。當 Spring 應用需要進行資源訪問時,它并不需要直接使用 Resource 實現類,而是調用 ApplicationContext 實例的 getResource() 方法來獲得資源,ApplicationContext 將會負責選擇 Resource 的實現類,也就是確定具體的資源訪問策略,從而將應用程序和具體的資源訪問策略分離開來。

ApplicationContext ctx = new Class PathXmlApplicationContext("bean.xml");
Resource res = ctx.getResource("book.xml");

上面的代碼中,Spring 將采用和 ApplicationContext 相同的策略來訪問資源。即: ApplicationContext 是 ClassPathXmlApplicationContext,則res 就是 ClassPathResource 實例。若將代碼改為:

ApplicationContext ctx = new Class FileSystemXmlApplicationContext("bean.xml");

則再次調用ctx.getResource時,res 就是 ClassPathResource 實例。

4、裝飾器模式

【參考】:裝飾器模式

4.1、定義

通過使用修飾模式,可以在運行時擴充一個類的功能。原理是:增加一個修飾類包裹原來的類,包裹的方式一般是通過在將原來的對象作為修飾類的構造函數的參數。裝飾類實現新的功能,但是,在不需要用到新功能的地方,它可以直接調用原來的類中的方法。修飾類必須和原來的類有相同的接口。

4.2、Spring中裝飾器模式的使用

Spring中類中帶有Wrapper的都是包裝類,如下創(chuàng)建bean就是典型的裝飾器模式

BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
    instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
    //根據指定的bean使用對應的側臉創(chuàng)建新的實例,如工廠方法,構造函數自動注入,簡單初始化
    instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
mbd.resolvedTargetType = beanType;
if (beanType != null) {
    // Allow post-processors to modify the merged bean definition.
    synchronized (mbd.postProcessingLock) {
        if (!mbd.postProcessed) {
            try {
                applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
            }
            catch (Throwable ex) {
                throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                        "Post-processing of merged bean definition failed", ex);
            }
            mbd.postProcessed = true;
        }
    }
}

寫在最后

當然Spring-IOC中還有很多的設計模式,比如代理,代理模式會放到AOP源碼分析那里去講解,那里才是代理模式的大量使用。
<iframe frameborder="no" border="0" marginwidth="0" marginheight="20" width=198 height=52 src="https://music.163.com/outchain/player?type=2&id=487587201&auto=1&height=32"></iframe>

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容