天天看點

Spring系列--spring IOC用到的設計模式前言叙述

文章目錄

  • 前言
  • 叙述
    • 工廠模式
    • 單例模式
    • 政策模式
    • 裝飾者模式

前言

Spring作為一款及其優秀的架構,其代碼的編寫非常優秀,裡面采用了大量的設計模式。

叙述

Spring IOC 容器就像是一個工廠一樣,當我們需要建立一個對象的時候,隻需要配置好配置檔案/注解即可,完全不用考慮對象是如何被建立出來的。IOC 容器負責建立對象,将對象連接配接在一起,配置這些對象,并從建立中處理這些對象的整個生命周期,直到它們被完全銷毀。

工廠模式

Spring使用工廠模式可以通過 BeanFactory 或 ApplicationContext 建立 bean 對象。

兩者對比:

  • BeanFactory :延遲注入(使用到某個 bean 的時候才會注入),相比于ApplicationContext 來說會占用更少的記憶體,程式啟動速度更快。
  • ApplicationContext :容器啟動的時候,不管你用沒用到,一次性建立所有 bean 。BeanFactory 僅提供了最基本的依賴注入支援,ApplicationContext 擴充了 BeanFactory ,除了有BeanFactory的功能還有額外更多功能,是以一般開發人員使用ApplicationContext會更多。

Spring 實作單例的方式:

ApplicationContext的三個實作類:

ClassPathXmlApplication:把上下文檔案當成類路徑資源。

FileSystemXmlApplication:從檔案系統中的 XML 檔案載入上下文定義資訊。

XmlWebApplicationContext:從Web系統中的XML檔案載入上下文定義資訊。

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
 
public class App {
	public static void main(String[] args) {
		ApplicationContext context = new FileSystemXmlApplicationContext(
				"C:/work/IOC Containers/springframework.applicationcontext/src/main/resources/bean-factory-config.xml");
 
		HelloApplicationContext obj = (HelloApplicationContext) context.getBean("helloApplicationContext");
		obj.getMsg();
	}
}

           

單例模式

Spring 中 bean 的預設作用域就是 singleton(單例)的。

Spring 實作單例的方式:

xml : <bean id="userService" class="top.snailclimb.UserService" scope="singleton"/>
注解:@Scope(value = "singleton")
           

Spring 通過 ConcurrentHashMap 實作單例系統資料庫的特殊方式實作單例模式。Spring 實作單例的核心代碼如下

// 通過 ConcurrentHashMap(線程安全) 實作單例系統資料庫
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(64);

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
        Assert.notNull(beanName, "'beanName' must not be null");
        synchronized (this.singletonObjects) {
            // 檢查緩存中是否存在執行個體  
            Object singletonObject = this.singletonObjects.get(beanName);
            if (singletonObject == null) {
                //...省略了很多代碼
                try {
                    singletonObject = singletonFactory.getObject();
                }
                //...省略了很多代碼
                // 如果執行個體對象在不存在,我們注冊到單例系統資料庫中。
                addSingleton(beanName, singletonObject);
            }
            return (singletonObject != NULL_OBJECT ? singletonObject : null);
        }
    }
    //将對象添加到單例系統資料庫
    protected void addSingleton(String beanName, Object singletonObject) {
            synchronized (this.singletonObjects) {
                this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT));

            }
        }
}

           

政策模式

在政策模式(Strategy Pattern)中,一個類的行為或其算法可以在運作時更改。這種類型的設計模式屬于行為型模式。在政策模式中,我們建立表示各種政策的對象和一個行為随着政策對象改變而改變的 context 對象。政策對象改變 context 對象的執行算法。政策模式實際就是一堆算法族的封裝。

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 執行個體。

裝飾者模式

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

Spring中裝飾器模式的使用

Spring中類中帶有Wrapper的都是包裝類,如下建立bean就是典型的裝飾器模式

BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
    instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
    //根據指定的bean使用對應的側臉建立新的執行個體,如工廠方法,構造函數自動注入,簡單初始化
    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;
        }
    }
}

           

參考連結: https://www.jianshu.com/p/139f813fca80

感謝您的閱讀~~

繼續閱讀