適配器模式(Adapter Pattern) :將一個接口轉換成客戶希望的另一個接口,適配器模式使接口不兼容的那些類可以一起工作,其別名爲包裝器(Wrapper)。適配器模式既可以作爲類結構型模式,也可以作爲對象結構型模式。
模式結構
適配器模式包含如下角色:
- Target:目標抽象類
- Adapter:適配器類
- Adaptee:適配者類
- Client:客戶類
<!--more-->
源碼導讀
我們都知道springMVC就用到了適配器模式,那他是怎麼適配呢,我們來看看它的源碼,首先我們要清楚springMVC的執行原理,它的整個流程我這裏就不像述了,說一下關鍵的部分:
-
DispatcherServlte
會根據配置文件信息註冊HandlerAdapter
,如果在配置文件中沒有配置,那麼DispatcherServlte
會獲取HandlerAdapter
的默認配置,如果是讀取默認配置的話,DispatcherServlte
會讀取DispatcherServlte.properties
文件,該文件中配置了三種HandlerAdapter
:HttpRequestHandlerAdapter
,SimpleControllerHandlerAdapter
和AnnotationMethodHandlerAdapter
。DispatcherServlte
會將這三個HandlerAdapter
對象存儲到它的handlerAdapters
這個集合屬性中,這樣就完成了HandlerAdapter
的註冊。 -
DispatcherServlte
會根據handlerMapping
傳過來的controller
與已經註冊好了的HandlerAdapter
一一匹配,看哪一種HandlerAdapter
是支持該controller類型的,如果找到了其中一種HandlerAdapter
是支持傳過來的controller
類型,那麼該HandlerAdapter
會調用自己的handle方法,handle方法運用java的反射機制執行controller的具體方法來獲得ModelAndView
DispatcherServlte
部分源碼
public class DispatcherServlet extends FrameworkServlet {
......
......
@Nullable
private List<HandlerMapping> handlerMappings;
@Nullable
private List<HandlerAdapter> handlerAdapters;
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
try {
ModelAndView mv = null;
Object dispatchException = null;
try {
......
......
HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
......
......
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
this.applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
} catch (Exception var20) {
dispatchException = var20;
} catch (Throwable var21) {
......
}
......
} catch (Exception var22) {
......
} catch (Throwable var23) {
......
}
} finally {
......
......
}
}
}
這裏只放上比較關鍵的代碼,我們可以看到當一個請求進入doDispatch()
方法的時候,它先去getHandlerAdapter()
中拿到適配器,這就是第二步中根據handlerMapping
中的controller
找到對應適配器。找到適配器後通過ha.handle(processedRequest, response, mappedHandler.getHandler())
執行我們自己的controller
,mappedHandler.getHandler()
就是我們自己的controller
。
至於handler()
如何知道該去執行controller中哪個方法,當然是通過註解去轉換對應方法的。因此,這裏的適配器模式還不是特別的純粹,還結合了反射機制。DispatcherServlte
屬於客戶端,我們的Controller
屬於被適配的類,HandlerAdapter
屬於適配器。
現在我們假定需要寫一個線程池任務調度框架,我們知道JDK自帶的線程框架可以創建一個線程池,但是線程池只能傳入實現runnable
接口或者callable
接口的對象。
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
cachedThreadPool.execute(new Runnable() {
@Override
public void run() {
}
})
那我們要咋樣可以讓客戶端使用的時候無須繼承runnable
來使用我們的這個框架呢。你可以像springMVC一樣使用適配器加註解。也可以提供一個實現Runnable
接口的抽象適配器類,讓客戶端進行一定的配置來將普通的類適配到Runnable
。
關於適配器的使用方面還有很多,比如spring security
的WebSecurityConfigurerAdapter
和netty
中的ChannelInboundHandlerAdapter
對於適配器模式類名一般都以Adapter
結尾