Spring 中經(jīng)典的 9 種設(shè)計模式,打死也要記住啊!

來源:blog.csdn.net/caoxiaohong1005
Spring中涉及的設(shè)計模式總結(jié),建議,收藏轉(zhuǎn)發(fā),保存
1.簡單工廠(非23種設(shè)計模式中的一種)
實現(xiàn)方式:
實質(zhì):
由一個工廠類根據(jù)傳入的參數(shù),動態(tài)決定應(yīng)該創(chuàng)建哪一個產(chǎn)品類。
實現(xiàn)原理:
1、讀取bean的xml配置文件,將bean元素分別轉(zhuǎn)換成一個BeanDefinition對象。
2、然后通過BeanDefinitionRegistry將這些bean注冊到beanFactory中,保存在它的一個ConcurrentHashMap中。
4、典型的例子就是:PropertyPlaceholderConfigurer,我們一般在配置數(shù)據(jù)庫的dataSource時使用到的占位符的值,就是它注入進去的。
實例化階段主要是通過反射或者CGLIB對bean進行實例化,在這個階段Spring又給我們暴露了很多的擴展點:
設(shè)計意義:
2.工廠方法
實現(xiàn)方式:
實現(xiàn)原理:
例子:
代碼示例:

3.單例模式
public Object getSingleton(String beanName){
//參數(shù)true設(shè)置標識允許早期依賴
return getSingleton(beanName,true);
}
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//檢查緩存中是否存在實例
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
//如果為空,則鎖定全局變量并進行處理。
synchronized (this.singletonObjects) {
//如果此bean正在加載,則不處理
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
//當某些方法需要提前初始化的時候則會調(diào)用addSingleFactory 方法將對應(yīng)的ObjectFactory初始化策略存儲在singletonFactories
ObjectFactory> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
//調(diào)用預(yù)先設(shè)定的getObject方法
singletonObject = singletonFactory.getObject();
//記錄在緩存中,earlysingletonObjects和singletonFactories互斥
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
getSingleton()過程圖
ps:spring依賴注入時,使用了 雙重判斷加鎖 的單例模式

單例模式定義:?保證一個類僅有一個實例,并提供一個訪問它的全局訪問點。
4.適配器模式
實現(xiàn)方式:
實現(xiàn)原理:
HandlerAdatper根據(jù)Handler規(guī)則執(zhí)行不同的Handler。
實現(xiàn)過程:
DispatcherServlet根據(jù)HandlerMapping返回的handler,向HandlerAdatper發(fā)起請求,處理Handler。
實現(xiàn)意義:
HandlerAdatper使得Handler的擴展變得容易,只需要增加一個新的Handler和一個對應(yīng)的HandlerAdapter即可。
5.裝飾器模式
實現(xiàn)方式:
Spring中用到的包裝器模式在類名上有兩種表現(xiàn):一種是類名中含有Wrapper,另一種是類名中含有Decorator。
實質(zhì):
就增加功能來說,Decorator模式相比生成子類更為靈活。
6.代理模式
實現(xiàn)方式:
動態(tài)代理:
靜態(tài)代理:
實現(xiàn)原理:
織入:把切面應(yīng)用到目標對象并創(chuàng)建新的代理對象的過程。
7.觀察者模式
實現(xiàn)方式:
spring的事件驅(qū)動模型使用的是 觀察者模式 ,Spring中Observer模式常用的地方是listener的實現(xiàn)。
具體實現(xiàn):
事件機制的實現(xiàn)需要三個部分,事件源,事件,事件監(jiān)聽器
ApplicationEvent抽象類[事件]
繼承自jdk的EventObject,所有的事件都需要繼承ApplicationEvent,并且通過構(gòu)造器參數(shù)source得到事件源.
該類的實現(xiàn)類ApplicationContextEvent表示ApplicaitonContext的容器事件.
代碼:
publicabstractclass ApplicationEvent extends EventObject {
privatestaticfinallong serialVersionUID = 7099057708183571937L;
privatefinallong timestamp;
public ApplicationEvent(Object source) {
super(source);
this.timestamp = System.currentTimeMillis();
}
public final long getTimestamp() {
returnthis.timestamp;
}
}
ApplicationListener接口[事件監(jiān)聽器]
繼承自jdk的EventListener,所有的監(jiān)聽器都要實現(xiàn)這個接口。
這個接口只有一個onApplicationEvent()方法,該方法接受一個ApplicationEvent或其子類對象作為參數(shù),在方法體中,可以通過不同對Event類的判斷來進行相應(yīng)的處理。
當事件觸發(fā)時所有的監(jiān)聽器都會收到消息。
代碼:
publicinterface ApplicationListener<E extends ApplicationEvent> extends EventListener {
void onApplicationEvent(E event);
}
ApplicationContext接口[事件源]
ApplicationContext是spring中的全局容器,翻譯過來是”應(yīng)用上下文”。
實現(xiàn)了ApplicationEventPublisher接口。
職責:
負責讀取bean的配置文檔,管理bean的加載,維護bean之間的依賴關(guān)系,可以說是負責bean的整個生命周期,再通俗一點就是我們平時所說的IOC容器。
代碼:
publicinterface ApplicationEventPublisher {
void publishEvent(ApplicationEvent event);
}
public void publishEvent(ApplicationEvent event) {
Assert.notNull(event, "Event must not be null");
if (logger.isTraceEnabled()) {
logger.trace("Publishing event in " + getDisplayName() + ": " + event);
}
getApplicationEventMulticaster().multicastEvent(event);
if (this.parent != null) {
this.parent.publishEvent(event);
}
}
ApplicationEventMulticaster抽象類[事件源中publishEvent方法需要調(diào)用其方法getApplicationEventMulticaster]
屬于事件廣播器,它的作用是把Applicationcontext發(fā)布的Event廣播給所有的監(jiān)聽器.
代碼:
publicabstractclass AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext, DisposableBean {
private ApplicationEventMulticaster applicationEventMulticaster;
protected void registerListeners() {
// Register statically specified listeners first.
for (ApplicationListener> listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener);
}
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let post-processors apply to them!
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String lisName : listenerBeanNames) {
getApplicationEventMulticaster().addApplicationListenerBean(lisName);
}
}
}
8.策略模式
實現(xiàn)方式:
Spring框架的資源訪問Resource接口。該接口提供了更強的資源訪問能力,Spring 框架本身大量使用了 Resource 接口來訪問底層資源。
Resource 接口介紹
source 接口是具體資源訪問策略的抽象,也是所有資源訪問類所實現(xiàn)的接口。
最后兩個方法通常無須使用,僅在通過簡單方式訪問無法實現(xiàn)時,Resource 提供傳統(tǒng)的資源訪問的功能。
Spring 為 Resource 接口提供了如下實現(xiàn)類:
這些 Resource 實現(xiàn)類,針對不同的的底層資源,提供了相應(yīng)的資源訪問邏輯,并提供便捷的包裝,以利于客戶端程序的資源訪問。
9.模版方法模式
經(jīng)典模板方法定義:
父類定義了骨架(調(diào)用哪些方法及順序),某些特定方法由子類實現(xiàn)。
最大的好處:代碼復(fù)用,減少重復(fù)代碼。除了子類要實現(xiàn)的特定方法,其他方法及方法調(diào)用順序都在父類中預(yù)先寫好了。
注:為什么叫鉤子,子類可以通過這個鉤子(方法),控制父類,因為這個鉤子實際是父類的方法(空方法)!
Spring模板方法模式實質(zhì):
是模板方法模式和回調(diào)模式的結(jié)合,是Template Method不需要繼承的另一種實現(xiàn)方式。Spring幾乎所有的外接擴展都采用這種模式。
具體實現(xiàn):
JDBC的抽象和對Hibernate的集成,都采用了一種理念或者處理方式,那就是模板方法模式與相應(yīng)的Callback接口相結(jié)合。
采用模板方法模式是為了以一種統(tǒng)一而集中的方式來處理資源的獲取和釋放,以JdbcTempalte為例:
publicabstractclass JdbcTemplate {
publicfinal Object execute(String sql){
Connection con=null;
Statement stmt=null;
try{
con=getConnection();
stmt=con.createStatement();
Object retValue=executeWithStatement(stmt,sql);
return retValue;
}catch(SQLException e){
...
}finally{
closeStatement(stmt);
releaseConnection(con);
}
}
protectedabstract Object executeWithStatement(Statement stmt, String sql);
}
引入回調(diào)原因:
JdbcTemplate是抽象類,不能夠獨立使用,我們每次進行數(shù)據(jù)訪問的時候都要給出一個相應(yīng)的子類實現(xiàn),這樣肯定不方便,所以就引入了回調(diào)。
回調(diào)代碼
publicinterface StatementCallback{
Object doWithStatement(Statement stmt);
}
利用回調(diào)方法重寫JdbcTemplate方法
publicclass JdbcTemplate {
publicfinal Object execute(StatementCallback callback){
Connection con=null;
Statement stmt=null;
try{
con=getConnection();
stmt=con.createStatement();
Object retValue=callback.doWithStatement(stmt);
return retValue;
}catch(SQLException e){
...
}finally{
closeStatement(stmt);
releaseConnection(con);
}
}
...//其它方法定義
}
Jdbc使用方法如下:
JdbcTemplate jdbcTemplate=...;
final String sql=...;
StatementCallback callback=new StatementCallback(){
public Object=doWithStatement(Statement stmt){
return ...;
}
}
jdbcTemplate.execute(callback);
為什么JdbcTemplate沒有使用繼承?
因為這個類的方法太多,但是我們還是想用到JdbcTemplate已有的穩(wěn)定的、公用的數(shù)據(jù)庫連接,那么我們怎么辦呢?
我們可以把變化的東西抽出來作為一個參數(shù)傳入JdbcTemplate的方法中。但是變化的東西是一段代碼,而且這段代碼會用到JdbcTemplate中的變量。怎么辦?
那我們就用回調(diào)對象吧。在這個回調(diào)對象中定義一個操縱JdbcTemplate中變量的方法,我們?nèi)崿F(xiàn)這個方法,就把變化的東西集中到這里了。然后我們再傳入這個回調(diào)對象到JdbcTemplate,從而完成了調(diào)用。
PS:如果覺得我的分享不錯,歡迎大家隨手點贊、在看。
END
