Spring MVC 源碼分析
一、Spring MVC運行流程圖

二、源碼分析
第一步:發(fā)送請求
這里我們需要清楚的知道spring mvc的入口是org.springframework.web.servlet.DispatcherServlet#doDispatch()。
DispatcherServlet是SpringMVC中的前端控制器,負(fù)責(zé)接收request并將request轉(zhuǎn)發(fā)給對應(yīng)的處理組件。
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {}
可以看到參數(shù)是HttpServletRequest,HttpServletResponse,專門來處理請求,和相應(yīng)的。我們可以查看類圖清晰的知道其實DispatcherServlet也是一個實現(xiàn)了HtttServlet接口的,是一個標(biāo)準(zhǔn)的Servlet容器。

第二步:獲取handler
HanlerMapping是SpringMVC中完成url到Controller映射的組件,也就是每個url都有一個對應(yīng)的Handler去處理,而對應(yīng)的handler里有對應(yīng)的Controller。
首先,需要知道的是都有哪些handler,為什么會有這么多handler
- 有哪些handler

首先有這么多的handler,這個是在spring boot下進行的調(diào)試,如果只是單單的使用spring mvc,可能會少一個。
-
為什么有這么多的handler
因為歷史原因,Spring MVC 在發(fā)展的過程中有很多種寫法,其中最熟悉的寫法如下:
@RestController public class UserController { @GetMapping("/hello") public String sayHello() { return "hello"; } @PostMapping("/bye") public String sayBye(){ return "bye"; } }但是在spring boot出現(xiàn)之前,或者在spring的早期版本中,還有如下寫法也可以處理客戶端請求
@Component("/demo3") public class ControllerDemo3 implements HttpRequestHandler { @Override public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { WebApplicationContext webApplicationContext = RequestContextUtils.findWebApplicationContext(request); System.out.println("===實現(xiàn)HttpRequestHandler接口==="); } }亦或是
@Component("/demo2") public class MyController implements Controller { @Override public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { System.out.println("123123"); return null; } }亦或是
@Component("/demo4") public class TemproController { public String sayHello(){ return "demo4"; } }每種寫法的背后都需要一種對應(yīng)的處理器去處理,因為寫法的不通,所以早就了這么多的handler。
其次,需要看spring 是如何查找handler的
-
在講解如何查找handler之前,需要先了解這里的設(shè)計結(jié)構(gòu)
- 具體查找如下,可以看到doDispatch方法如下

getHandler()方法如下
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
/**
* 通過for循環(huán)在所有的handlerMappings里查找對應(yīng)的handler。
* 怎么查找繼續(xù)看mapping.getHandler()
*
*/
for (HandlerMapping mapping : this.handlerMappings) {
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
Object handler = getHandlerInternal(request);
......
}
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
//這里可以看到lookupPath就是我們請求的路徑 如:/demo3
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
request.setAttribute(LOOKUP_PATH, lookupPath);
this.mappingRegistry.acquireReadLock();
try {
//這里lookupHandlerMethod就是查找handler的地方
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
finally {
this.mappingRegistry.releaseReadLock();
}
}
重點來了,這里就是最終查找handler的方法
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<Match> matches = new ArrayList<>();
//①
List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
if (directPathMatches != null) {
addMatchingMappings(directPathMatches, matches, request);
}
if (matches.isEmpty()) {
// No choice but to go through all mappings...
addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
}
if (!matches.isEmpty()) {
Match bestMatch = matches.get(0);
if (matches.size() > 1) {
Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
matches.sort(comparator);
bestMatch = matches.get(0);
if (logger.isTraceEnabled()) {
logger.trace(matches.size() + " matching mappings: " + matches);
}
if (CorsUtils.isPreFlightRequest(request)) {
return PREFLIGHT_AMBIGUOUS_MATCH;
}
Match secondBestMatch = matches.get(1);
if (comparator.compare(bestMatch, secondBestMatch) == 0) {
Method m1 = bestMatch.handlerMethod.getMethod();
Method m2 = secondBestMatch.handlerMethod.getMethod();
String uri = request.getRequestURI();
throw new IllegalStateException(
"Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");
}
}
request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);
handleMatch(bestMatch.mapping, lookupPath, request);
return bestMatch.handlerMethod;
}
else {
return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
}
}
①處調(diào)試代碼如下:

可以看到所有的請求地址都在LinkedMultivalueMap中,這里沒有匹配到,如果沒有匹配到最后

,這里在第二輪的查找中找到了,如下:

這里找到handler之后,在看是如何返回的,返回的過程中,有沒有對此ControdderDemo3做過什么修改。我們看到最后return了一個buildPathExposingHandler。這個方法具體做了什么,我們接著往下看
protected Object buildPathExposingHandler(Object rawHandler, String bestMatchingPattern,
String pathWithinMapping, @Nullable Map<String, String> uriTemplateVariables) {
/**
* 這里使用了HandlerExecutionChain把原有的處理器給包裹了,并暴露請求的路徑地址以及uri模板變量。
* 這里為什么包裹了,后面再說......
*/
HandlerExecutionChain chain = new HandlerExecutionChain(rawHandler);
chain.addInterceptor(new PathExposingHandlerInterceptor(bestMatchingPattern, pathWithinMapping));
if (!CollectionUtils.isEmpty(uriTemplateVariables)) {
chain.addInterceptor(new UriTemplateVariablesHandlerInterceptor(uriTemplateVariables));
}
return chain;
}
也就是說這里返回了一個包含原有處理器的HandlerExecutionChain,并且HandlerExecutionChain內(nèi)新增了了一個會攔截請求的攔截器。
如下:

也就是說

這個lookupHandler返回了一個包裝了原有處理器ControllerDemo3和攔截/demo3的攔截器的一個HandlerExecutionChain對象。
整體獲取Handler的流程圖如下:

第三步:獲取Adapter
核心代碼如下:
// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
//匹配適配器
for (HandlerAdapter adapter : this.handlerAdapters) {
if (adapter.supports(handler)) {
return adapter;
}
}
}
這里this.handlerAdapters與上一步中的this.handlerMappings有一定的對應(yīng)關(guān)系。如下圖:

這里匹配到了一個Adapter。

此時的HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());返回的ha就是HttpRequestHandlerAdapter
繼續(xù)往下執(zhí)行
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
handler方法:
//這個時候的handler參數(shù)實際是ControllerDemo3
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
//將ControllerDemo3強轉(zhuǎn)為父類型,調(diào)用handleRequest方法,實際調(diào)用的就是ControllerDemo3的handleRequest方法
((HttpRequestHandler) handler).handleRequest(request, response);
return null;
}
ControllerDemo3就是實現(xiàn)了HttpRequestHandler接口,代碼如下:
@Component("/demo3")
public class ControllerDemo3 implements HttpRequestHandler {
@Override
public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
WebApplicationContext webApplicationContext = RequestContextUtils.findWebApplicationContext(request);
System.out.println("===實現(xiàn)HttpRequestHandler接口===");
}
}
后續(xù)的流程這里不在分析了,至此Spring MVC的核心流程分析完畢。
三、HandlerMapping
public interface HandlerMapping {
獲取HandlerExecutionChain
HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}
一開始我們用了4中方式去實現(xiàn)一個自己的Controller。這4中Controller在spring啟動的時候,會被分門別類的去處理。寫法不同,處理方式肯定不同。雖然處理凡是不同,但是結(jié)果又都是相同的。所以這里抽象出一個接口,多個實現(xiàn)去在不通情況下獲取HandlerExecutionChain的。

這里以RequestMappinghandlerMapping為例進行分析

這里通過查找了解到,AbstractHandlerMethodMapping實現(xiàn)了HandlerMapping接口
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
Object handler = getHandlerInternal(request);
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
return executionChain;
}
getHandlerInternal的實現(xiàn)如下,中間省略了部分代碼:
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<Match> matches = new ArrayList<>();
// ①當(dāng)前這種handler的核心獲取方式是在
List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
if (directPathMatches != null) {
// ② 這里會在初始化后的mappingRegistry.getMappings()方法里找到匹配的自定義controller
addMatchingMappings(directPathMatches, matches, request);
}
if (!matches.isEmpty()) {
// ③獲取match
Match bestMatch = matches.get(0);
request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);
handleMatch(bestMatch.mapping, lookupPath, request);
// ④這里bestMatch.handlerMethod方法返回的就是UserController對象
return bestMatch.handlerMethod;
}
else {
return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
}
}

返回的UserController對象又回被封裝成HandlerExecutionChain對象。執(zhí)行和前面分析的邏輯一樣。
四、這里在分析HandlerAdapter接口
public interface HandlerAdapter {
boolean supports(Object handler);
@Nullable
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
long getLastModified(HttpServletRequest request, Object handler);
handlerAdapter的實現(xiàn):

這里針對不通寫法的controller,對應(yīng)不通的xxxAdapter適配器。這里我們以RequestMappingHanderAdapter為例分析一下,這個也是適配如下的controller
@RestController
public class UserController {
@GetMapping("/hello")
public String sayHello() {
return "hello";
}
}
至于為什么處理的是這種controller,我們可以看下HandlerAdapter接口的supports實現(xiàn),也就是RequestMappingHanderAdapter實現(xiàn)類中的supports方法即可知道原因。
@Override
public final boolean supports(Object handler) {
return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}
@Override
protected boolean supportsInternal(HandlerMethod handlerMethod) {
return true;
}
這里我們只需關(guān)注handler instanceof HandlerMethod 這里返回的true,所以也就是RequestMappingHanderAdapter來處理UserContoller了。這里我們也看到了UserContoller類也沒有實現(xiàn)任何抽象,那么UserContoller又如何是HandlerMethod類型呢,后面接著說。這里RequestMappingHanderAdapter最后也是通過反射調(diào)到了實際的controller#sayHello()方法,反射在這里就不過多贅述了。其他的HandlerAdapter實現(xiàn)通過同樣的方式去分析也就清楚了這里為什么要有適配器。
五、Controller和HandlerMethod
RequestMappingHandlerMapping實現(xiàn)了InitializingBean接口,在afterPropertiesSet()方法了,完成UserController到HandlerMethod類型的轉(zhuǎn)變。
public void afterPropertiesSet() {
......
super.afterPropertiesSet();
}
父類方法:
public void afterPropertiesSet() {
initHandlerMethods();
}
protected void initHandlerMethods() {
for (String beanName : getCandidateBeanNames()) {
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
//重點在這里
processCandidateBean(beanName);
}
}
handlerMethodsInitialized(getHandlerMethods());
}
protected void processCandidateBean(String beanName) {
......
if (beanType != null && isHandler(beanType)) {
//進入這里
detectHandlerMethods(beanName);
}
}
protected void detectHandlerMethods(Object handler) {
Class<?> handlerType = (handler instanceof String ?
obtainApplicationContext().getType((String) handler) : handler.getClass());
if (handlerType != null) {
Class<?> userType = ClassUtils.getUserClass(handlerType);
// 看圖3就很清楚當(dāng)前代碼的作用了。不過我們的關(guān)注點在第四步
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
(MethodIntrospector.MetadataLookup<T>) method -> {
try {
return getMappingForMethod(method, userType);
}
catch (Throwable ex) {
throw new IllegalStateException("Invalid mapping on handler class [" +
userType.getName() + "]: " + method, ex);
}
});
methods.forEach((method, mapping) -> {
Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
//看這里 第四步
registerHandlerMethod(handler, invocableMethod, mapping);
});
}
}

圖3:

接著看registerHandlerMethod(handler, invocableMethod, mapping);
跟下去,會跟到如下代碼
AbstractHandlerMethodMapping.java
public void register(T mapping, Object handler, Method method) {
// Assert that the handler method is not a suspending one.
if (KotlinDetector.isKotlinType(method.getDeclaringClass())) {
Class<?>[] parameterTypes = method.getParameterTypes();
if ((parameterTypes.length > 0) && "kotlin.coroutines.Continuation".equals(parameterTypes[parameterTypes.length - 1].getName())) {
throw new IllegalStateException("Unsupported suspending handler method detected: " + method);
}
}
this.readWriteLock.writeLock().lock();
try {
HandlerMethod handlerMethod = createHandlerMethod(handler, method);
......
}
......
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 重點 //
// 重點 //
// 重點 //
// 重點 //
// 重點 //
//這個方法就是把handler封裝一下,最后返回HandlerMethod,這里最后也就說明了為什么我們自定義的Controller的類型是HandlerMethod了//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
protected HandlerMethod createHandlerMethod(Object handler, Method method) {
if (handler instanceof String) {
//看這里,明白了一切
return new HandlerMethod((String) handler,
obtainApplicationContext().getAutowireCapableBeanFactory(), method);
}
return new HandlerMethod(handler, method);
}
這里在提一個問題,為什么要把Controller封裝成HandlerMethod?這里是因為controller的方法有很多,如果不用HandlerMethod這個通用的類去封裝的話,一些其他功能實現(xiàn)起來可能就比較麻煩了。比如HandlerInterceptor接口,比如我們實現(xiàn)了這么一個接口
@Component
public class MyInterceptor extends HandlerInterceptorAdapter {
//如果這里不使用handler,傳入的事controller,那么到了調(diào)用父類的super.preHandle方法就沒法適配其他controller的方法了
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("handler is executed!!!!!!!");
return super.preHandle(request, response, handler);
}
......
}
看下HandlerMethod的注釋
/**
* Encapsulates information about a handler method consisting of a
* {@linkplain #getMethod() method} and a {@linkplain #getBean() bean}.
* Provides convenient access to method parameters, the method return value,
* method annotations, etc.
*
* <p>The class may be created with a bean instance or with a bean name
* (e.g. lazy-init bean, prototype bean). Use {@link #createWithResolvedBean()}
* to obtain a {@code HandlerMethod} instance with a bean instance resolved
* through the associated {@link BeanFactory}.
*/
public class HandlerMethod {}
大意就是:
HandlerMethod封裝了很多屬性,在訪問請求方法的時候可以方便的訪問到方法、方法參數(shù)、方法上的注解、所屬類等并且對方法參數(shù)封裝處理,也可以方便的訪問到方法參數(shù)的注解等信息