適配器模式(Adapter Pattern) :將一個(gè)接口轉(zhuǎn)換成客戶(hù)希望的另一個(gè)接口,適配器模式使接口不兼容的那些類(lèi)可以一起工作,其別名為包裝器(Wrapper)。適配器模式既可以作為類(lèi)結(jié)構(gòu)型模式,也可以作為對(duì)象結(jié)構(gòu)型模式。
模式結(jié)構(gòu)
適配器模式包含如下角色:
- Target:目標(biāo)抽象類(lèi)
- Adapter:適配器類(lèi)
- Adaptee:適配者類(lèi)
- Client:客戶(hù)類(lèi)
源碼導(dǎo)讀
我們都知道springMVC就用到了適配器模式,那他是怎么適配呢,我們來(lái)看看它的源碼,首先我們要清楚springMVC的執(zhí)行原理,它的整個(gè)流程我這里就不像述了,說(shuō)一下關(guān)鍵的部分:
-
DispatcherServlte會(huì)根據(jù)配置文件信息注冊(cè)HandlerAdapter,如果在配置文件中沒(méi)有配置,那么DispatcherServlte會(huì)獲取HandlerAdapter的默認(rèn)配置,如果是讀取默認(rèn)配置的話(huà),DispatcherServlte會(huì)讀取DispatcherServlte.properties文件,該文件中配置了三種HandlerAdapter:HttpRequestHandlerAdapter,SimpleControllerHandlerAdapter和AnnotationMethodHandlerAdapter。DispatcherServlte會(huì)將這三個(gè)HandlerAdapter對(duì)象存儲(chǔ)到它的handlerAdapters這個(gè)集合屬性中,這樣就完成了HandlerAdapter的注冊(cè)。 -
DispatcherServlte會(huì)根據(jù)handlerMapping傳過(guò)來(lái)的controller與已經(jīng)注冊(cè)好了的HandlerAdapter一一匹配,看哪一種HandlerAdapter是支持該controller類(lèi)型的,如果找到了其中一種HandlerAdapter是支持傳過(guò)來(lái)的controller類(lèi)型,那么該HandlerAdapter會(huì)調(diào)用自己的handle方法,handle方法運(yùn)用java的反射機(jī)制執(zhí)行controller的具體方法來(lái)獲得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 {
......
......
}
}
}
這里只放上比較關(guān)鍵的代碼,我們可以看到當(dāng)一個(gè)請(qǐng)求進(jìn)入doDispatch()方法的時(shí)候,它先去getHandlerAdapter()中拿到適配器,這就是第二步中根據(jù)handlerMapping中的controller找到對(duì)應(yīng)適配器。找到適配器后通過(guò)ha.handle(processedRequest, response, mappedHandler.getHandler())執(zhí)行我們自己的controller,mappedHandler.getHandler()就是我們自己的controller。
至于handler()如何知道該去執(zhí)行controller中哪個(gè)方法,當(dāng)然是通過(guò)注解去轉(zhuǎn)換對(duì)應(yīng)方法的。因此,這里的適配器模式還不是特別的純粹,還結(jié)合了反射機(jī)制。DispatcherServlte屬于客戶(hù)端,我們的Controller屬于被適配的類(lèi),HandlerAdapter屬于適配器。
現(xiàn)在我們假定需要寫(xiě)一個(gè)線程池任務(wù)調(diào)度框架,我們知道JDK自帶的線程框架可以創(chuàng)建一個(gè)線程池,但是線程池只能傳入實(shí)現(xiàn)runnable接口或者callable接口的對(duì)象。
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
cachedThreadPool.execute(new Runnable() {
@Override
public void run() {
}
})
那我們要咋樣可以讓客戶(hù)端使用的時(shí)候無(wú)須繼承runnable來(lái)使用我們的這個(gè)框架呢。你可以像springMVC一樣使用適配器加注解。也可以提供一個(gè)實(shí)現(xiàn)Runnable接口的抽象適配器類(lèi),讓客戶(hù)端進(jìn)行一定的配置來(lái)將普通的類(lèi)適配到Runnable。
關(guān)于適配器的使用方面還有很多,比如spring security的WebSecurityConfigurerAdapter和netty中的ChannelInboundHandlerAdapter 對(duì)于適配器模式類(lèi)名一般都以Adapter結(jié)尾
