前言
接上一篇講下spring-ioc中的設(shè)計(jì)模式。Spring作為一款及其優(yōu)秀的框架董习,其代碼的編寫非常優(yōu)秀,里面采用了大量的設(shè)計(jì)模式爱只。下面我們一點(diǎn)點(diǎn)分析皿淋。
先簡單說下常見的設(shè)計(jì)模式
- 1、工廠模式
- 2宋距、單例模式
- 3衰腌、策略模式
- 4推正、裝飾器模式
1、工廠模式
【參考】:工廠模式的區(qū)別
1.1哑舒、定義
工廠模式可將Java對(duì)象的調(diào)用者從被調(diào)用者的實(shí)現(xiàn)邏輯中分離出來,調(diào)用者只需關(guān)心被調(diào)用者必須滿足的規(guī)則(接口)幻馁,而不必關(guān)心實(shí)例的具體實(shí)現(xiàn)過程散址。工廠模式由抽象產(chǎn)品(接口)乖阵、具體產(chǎn)品(實(shí)現(xiàn)類)、生產(chǎn)者(工廠類)三種角色組成预麸。
1.2瞪浸、Spring中工廠模式的應(yīng)用
Spring中在各種BeanFactory以及ApplicationContext創(chuàng)建中都用到了典型的工廠方法模式。ApplicationContext的設(shè)計(jì)圖如下吏祸,SpringBean的體系結(jié)構(gòu)比較復(fù)雜对蒲,頂級(jí)接口是BeanFactory;BeanFactory共有三個(gè)子接口:ListableBeanFactory贡翘、HierarchicalBeanFactory和AutowireCapableBeanFactory蹈矮,還有一個(gè)SimpleJndiBeanFactory實(shí)現(xiàn)類。這三個(gè)子接口集成了頂級(jí)接口并對(duì)BeanFactory的功能進(jìn)行了增強(qiáng)鸣驱,稱為二級(jí)接口泛鸟;ConfigurableBeanFactory對(duì)二級(jí)接口HierarchicalBeanFactory進(jìn)行了再次增強(qiáng),它還繼承了另一個(gè)外來的接口SingletonBeanRegistry踊东,可以被稱為三級(jí)接口北滥;ConfigurableListableBeanFactory是一個(gè)更強(qiáng)大的接口,繼承了上述的所有接口闸翅,稱為四級(jí)接口再芋。其余的為抽象類,實(shí)現(xiàn)了Spring Bean四級(jí)接口所定義的所有功能坚冀。

2济赎、單例模式
【參考】: 單例
2.1、定義
單例模式具有以下特點(diǎn):
- 1记某、單例類只能有一個(gè)實(shí)例司训。
- 2、單例類必須自己創(chuàng)建自己的唯一實(shí)例液南。
- 3豁遭、單例類必須給所有其他對(duì)象提供這一實(shí)例
2.2 Spring中單例模式的使用
在Spring中,所有的bean默認(rèn)都是單例創(chuàng)建的贺拣。在創(chuàng)建bean的代碼中我們經(jīng)潮托唬看到Singleton這個(gè)單詞。下面我們通過代碼看看單例是怎么實(shí)現(xiàn)的譬涡。
【AbstractBeanFactory】
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
·············
//實(shí)例化依賴的bean之后可以實(shí)例化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);
}
···········
}
通過將工廠函數(shù)傳入getSingleton函數(shù)中闪幽,就可以獲得一個(gè)Bean單例。單例的生成是通過修改createBean函數(shù)的參數(shù)實(shí)現(xiàn)的涡匀,其中mbd是一個(gè)RootBeanDefinition類盯腌,它存儲(chǔ)了生成Bean實(shí)例所需要的信息。在createBean之中的代碼里陨瘩,程序調(diào)用實(shí)例化Bean的函數(shù)initializeBean
3腕够、策略模式
【參考】:策略模式
3.1 定義
在策略模式(Strategy Pattern)中级乍,一個(gè)類的行為或其算法可以在運(yùn)行時(shí)更改。這種類型的設(shè)計(jì)模式屬于行為型模式帚湘。在策略模式中玫荣,我們創(chuàng)建表示各種策略的對(duì)象和一個(gè)行為隨著策略對(duì)象改變而改變的 context 對(duì)象。策略對(duì)象改變 context 對(duì)象的執(zhí)行算法大诸。策略模式實(shí)際就是一堆算法族的封裝捅厂。
3.2 Spring中策略模式的應(yīng)用
當(dāng)bean需要訪問資源配置文件時(shí),Spring有兩種方式
- 代碼中獲取Rescource實(shí)例
- 依賴注入
第一種方式需要獲取rescource資源的位置资柔,代碼中耦合性太高焙贷,而今我們一直使用注解,依賴注入的方式去獲取贿堰。這樣的話就無需修改程序辙芍,只改配置文件即可。
<beans>
<bean id="test" class="com.example.Test">
<!-- 注入資源 -->
<property name="tmp" value="classpath:book.xml"/>
</bean>
</beans>
在依賴注入的過程中羹与,Spring會(huì)調(diào)用ApplicationContext 來獲取Resource的實(shí)例故硅。然而,Resource 接口封裝了各種可能的資源類型注簿,包括了:UrlResource契吉,ClassPathResource跳仿,F(xiàn)ileSystemResource等诡渴,Spring需要針對(duì)不同的資源采取不同的訪問策略。在這里菲语,Spring讓ApplicationContext成為了資源訪問策略的“決策者”妄辩。在資源訪問策略的選擇上,Spring采用了策略模式山上。當(dāng) Spring 應(yīng)用需要進(jìn)行資源訪問時(shí)眼耀,它并不需要直接使用 Resource 實(shí)現(xiàn)類,而是調(diào)用 ApplicationContext 實(shí)例的 getResource() 方法來獲得資源佩憾,ApplicationContext 將會(huì)負(fù)責(zé)選擇 Resource 的實(shí)現(xiàn)類哮伟,也就是確定具體的資源訪問策略,從而將應(yīng)用程序和具體的資源訪問策略分離開來妄帘。
ApplicationContext ctx = new Class PathXmlApplicationContext("bean.xml");
Resource res = ctx.getResource("book.xml");
上面的代碼中楞黄,Spring 將采用和 ApplicationContext 相同的策略來訪問資源。即: ApplicationContext 是 ClassPathXmlApplicationContext抡驼,則res 就是 ClassPathResource 實(shí)例鬼廓。若將代碼改為:
ApplicationContext ctx = new Class FileSystemXmlApplicationContext("bean.xml");
則再次調(diào)用ctx.getResource時(shí),res 就是 ClassPathResource 實(shí)例致盟。
4碎税、裝飾器模式
【參考】:裝飾器模式
4.1尤慰、定義
通過使用修飾模式,可以在運(yùn)行時(shí)擴(kuò)充一個(gè)類的功能雷蹂。原理是:增加一個(gè)修飾類包裹原來的類伟端,包裹的方式一般是通過在將原來的對(duì)象作為修飾類的構(gòu)造函數(shù)的參數(shù)。裝飾類實(shí)現(xiàn)新的功能萎河,但是荔泳,在不需要用到新功能的地方,它可以直接調(diào)用原來的類中的方法虐杯。修飾類必須和原來的類有相同的接口玛歌。
4.2、Spring中裝飾器模式的使用
Spring中類中帶有Wrapper的都是包裝類擎椰,如下創(chuàng)建bean就是典型的裝飾器模式
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
//根據(jù)指定的bean使用對(duì)應(yīng)的側(cè)臉創(chuàng)建新的實(shí)例支子,如工廠方法,構(gòu)造函數(shù)自動(dò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;
}
}
}
寫在最后
當(dāng)然Spring-IOC中還有很多的設(shè)計(jì)模式值朋,比如代理,代理模式會(huì)放到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>