spring源码系列文章,示例代码的中文注释,均是 copy 自 https://gitee.com/wlizhi/spring-framework 。
链接中源码是作者从 github 下载,并以自身理解对核心流程及主要节点做了详细的中文注释。
1 处理请求的入口
根据 servlet 规范,当服务器在接收到请求时,会调用至 servlet.service() 方法,进行处理,DispatcherServlet 就是如此。
例如一个post请求,会经过以下调用:
service() -> doPost() -> processRequest() -> doService() -> doDispatch()
无论什么类型的请求,最终都会调用至 doDispatch()。
doDispatch() 源码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
|
public class DispatcherServlet extends FrameworkServlet {
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
/* TODO
预处理:
1. 获取HandlerMethod和过滤器链的包装类(url-hanlderMethod映射):HandlerExecutionChain,里面包含了handlerMethod对象
2. 根据handlerMethod对象,找到合适的HandlerAdapter对象,这里用到了策略模式
调用链:
1. 前置拦截,正向遍历调用,若有返回false,则调用后置处理,返回。
interceptor.preHandle(request, response, this.handler)
triggerAfterCompletion(request, response, null);
2. 根据HandlerAdapter获取真正的处理类,执行:((Controller) handler).handleRequest(request, response)
3. 中置拦截,反向遍历调用。 interceptor.postHandle(request, response, this.handler, mv);
4. 视图渲染,在视图渲染之后,会在视图渲染方法中调用后置处理。
render(mv, request, response);
if (mappedHandler != null) {
mappedHandler.triggerAfterCompletion(request, response, null);
}
*/
// 异步管理
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
// 文件上传
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// TODO 这个方法很重要,重点看 获取封装了 handlerMethod、拦截器的执行链封装 HandlerExecutionChain。
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// TODO 获取跟HandlerMethod匹配的HandlerAdapter对象
// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
// TODO 前置过滤器,如果为false则直接返回
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// TODO 调用到Controller具体方法,核心方法调用,重点看看
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
// TODO 执行中置拦截
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
// As of 4.3, we're processing Errors thrown from handler methods as well,
// making them available for @ExceptionHandler methods and other scenarios.
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
// TODO 处理结果,这里执行了后置拦截。在前面的流程里捕获了业务方法执行过程中抛出的异常。
// 如果上面的流程中抛出了异常,则dispatchException一定有值。
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
}
|
主要调用流程如下:
- 获取到 HandlerExecutionChain。其中封装了 handlerMethod 和 拦截器链。
- 获取 HandlerAdapter。
- 调用拦截器前置拦截方法 preHandle()。
- 调用 handle(),内部通过反射调用了controller中的业务方法。
- 调用 applyPostHandle(),执行中置拦截。
- 调用 processDispatchResult(),内部调用了全局异常处理和后置拦截。
前面五个步骤是在 try catch 块中执行的,如果执行中发生了异常,会被捕获到,变量 dispatchException 也就有值了,这时候才会触发全局异常处理。
2 getHandler() 获取handlerMethod及拦截器的封装类
getHandler() 源码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
public class DispatcherServlet extends FrameworkServlet {
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// handlerMappering实例
if (this.handlerMappings != null) {
// 在 DispatcherServlet 初始化的时候,会将handlerMappings的值,赋值到这里。
for (HandlerMapping mapping : this.handlerMappings) {
// 获取HandlerMethod和拦截器链的包装类
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
}
|
遍历 handlerMappings,依次调用 getHandler(),如果获取到执行链,就返回。
getHandler() 源码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport
implements HandlerMapping, Ordered, BeanNameAware {
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// TODO 获取 HandlerMethod
Object handler = getHandlerInternal(request);
if (handler == null) {
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = obtainApplicationContext().getBean(handlerName);
}
// TODO 将 handlerMethod,包装到 HandlerExecutionChain 中。
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
// 省略无关代码...
return executionChain;
}
}
|
这里有两个关键的方法调用,getHandlerInternal()、getHandlerExecutionChain()。
2.1 getHandlerInternal()
源码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean {
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
this.mappingRegistry.acquireReadLock();
try {
// 根据路径获取到 HandlerMapping,再根据 HandlerMapping 获取到 HandlerMethod
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
// TODO 因为在初始化 HandlerMethod 时,并没有将bean实例封装进去,只是封装了一个 beanClass 和 beanName。
// 如果获取到 handlerMethod 不为空,则会在这里进行 getBean 操作,将 bean 实例封装到 handlerMethod中。
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
finally {
this.mappingRegistry.releaseReadLock();
}
}
}
|
首先根据请求路径,获取到 HandlerMethod。如果 HandlerMethod 存在,则将内部封装的 beanName,通过调用 getBean(),获取到具体的实例,
将获取到的实例缓存到成员变量中,替换掉变量 beanName。
lookupHandlerMethod() 中,会首先通过 url 获取到 HandlerMappingInfo,再通过 HandlerMappingInfo 获取到具体的 handlerMethod。
lookupHandlerMethod中的部分源码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean {
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<Match> matches = new ArrayList<>();
// 根据url路径从 urlLookup 中获取 RequestMappingInfo
List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
if (directPathMatches != null) {
addMatchingMappings(directPathMatches, matches, request);
}
// 省略部分代码...
if (!matches.isEmpty()) {
// 获取最佳匹配,代码省略...
return bestMatch.handlerMethod;
} // 省略部分代码...
}
}
|
如以上源码,在 getMappingsByUrl() 中就获取了 RequestMappingInfo 实例列表。是从成员变量 urlLookup 中获取的。
addMatchingMappings() 中,从成员变来那个 mappingLookup 获取到了 handlerMethod。
源码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean {
private void addMatchingMappings(Collection<T> mappings, List<Match> matches, HttpServletRequest request) {
for (T mapping : mappings) {
T match = getMatchingMapping(mapping, request);
if (match != null) {
// 从 mappingLookup 中获取 handlerMethod
matches.add(new Match(match, this.mappingRegistry.getMappings().get(mapping)));
}
}
}
public Map<T, HandlerMethod> getMappings() {
return this.mappingLookup;
}
}
|
上面代码中,注意 getMappings() 方法返回的是 this.mappingLookup,这是一个 map 集合,封装了 RequestMappingInfo - HandlerMethod 的映射关系。
createWithResolvedBean() 源码:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
public class HandlerMethod {
public HandlerMethod createWithResolvedBean() {
Object handler = this.bean;
// 最初这个 bean 成员变量,只是设置了一个 beanName,因此它是字符串类型的,执行到这里会调用 getBean(),将真正的实例设置到这里。
// 如果已经设置过了,bean就不是字符串类型了,就不会进这个 if 语句。
if (this.bean instanceof String) {
Assert.state(this.beanFactory != null, "Cannot resolve bean name without BeanFactory");
String beanName = (String) this.bean;
handler = this.beanFactory.getBean(beanName);
}
return new HandlerMethod(this, handler);
}
}
|
前文中有提到,在 RequestMappingHandlerMapping 初始化的时候,是收集了HandlerMethod的,而在封装 HandlerMethod 时,并没有设置具体的 bean 实例,仅仅设置了 beanClass 以及 beanName。bean 的实例就是在这里进行设置的。
如上源码,当容器启动后,第一个请求进来时,this.bean 中存储的是 beanName,也就是一个字符串。这时候就会触发调用 getBean(),将 this.bean 的值替换为 bean 的实例对象。
后面再有请求过来,就不会再调用 getBean 了。这里的 new HandlerMethod(),类似于一种copy。因为在执行过程中,可能会修改内部封装的一些属性值,即每一个线程获取到的这个对象要是线程安全的(或者说是线程独立的),所以才要重新创建一个 HandlerMethod 实例。
2.2 getHandlerExecutionChain()
getHandlerExecutionChain() 源码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport
implements HandlerMapping, Ordered, BeanNameAware {
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
// 创建拦截器链
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
// 拦截器匹配,获取拦截器执行链
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
// 遍历所有的拦截器,如果是 MappedInterceptor,根据拦截器的 excludePatterns 和 includePatterns 来进行匹配。
// 如果没有配置 includePatterns 且在 excludePatterns 没有匹配到,则默认为 true。
// 也就是说 MappedInterceptor 中具有路径匹配功能,同时包装了一个 HandlerInterceptor 实现。
// 而 HandlerInterceptor 中仅仅定义了 前置、中置、后置拦截方法。
for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
if (interceptor instanceof MappedInterceptor) {
MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
}
else {
chain.addInterceptor(interceptor);
}
}
return chain;
}
}
|
首先创建 HandlerExecutionChain,将 HandlerMethod 封装。
遍历所有的拦截器,如果拦截器是 MappedInterceptor 类型,则调用 matches() 进行路径匹配,匹配为 true,就加入到拦截器执行链中。这里的拦截器链就是一个 List。
HandlerExecutionChain 的数据结构:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
public class HandlerExecutionChain {
private static final Log logger = LogFactory.getLog(HandlerExecutionChain.class);
/** 这里是一个 handlerMethod */
private final Object handler;
/** 拦截器 最终会合并到 interceptorList */
@Nullable
private HandlerInterceptor[] interceptors;
/** 拦截器 */
@Nullable
private List<HandlerInterceptor> interceptorList;
private int interceptorIndex = -1;
public void addInterceptor(HandlerInterceptor interceptor) {
initInterceptorList().add(interceptor);
}
private List<HandlerInterceptor> initInterceptorList() {
if (this.interceptorList == null) {
this.interceptorList = new ArrayList<>();
// 如果 interceptors 中有值,合并到 interceptorList 中。
if (this.interceptors != null) {
// An interceptor array specified through the constructor
CollectionUtils.mergeArrayIntoCollection(this.interceptors, this.interceptorList);
}
}
this.interceptors = null;
return this.interceptorList;
}
}
|
从其数据结构中可以看出,内部就是封装了 handler 和多个拦截器组成的 interceptorList 列表。
在添加拦截器时,会调用 initInterceptorList(),如果 interceptors 中有值,会合并到列表中。
如此,就将 HandlerMethod 以及匹配的拦截器封装为 HandlerExecutionChain 返回了。
3 getHandlerAdapter()
这里是典型的策略模式,从 handlerAdapters 中遍历,依次调用 supports() 判断是否支持当前的 handlerMethod,如果支持,就返回。如果最终未找到有支持的 HandlerAdapter,会抛出异常。
这也是为什么在初始化的时候,会默认注册那么多 HandlerAdapter 的原因。spring 考虑到了大多数的一些 参数、返回值 等的处理策略。
源码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
public class DispatcherServlet extends FrameworkServlet {
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
// 根据handlerMethod对象,找到合适的HandlerAdapter对象,这里是典型的的策略模式
// 遍历所有的 handlerAdapters,并调用其 supports(),如果有 adapter 支持这个 handlerMethod,就返回这个 adapter。
if (this.handlerAdapters != null) {
for (HandlerAdapter adapter : this.handlerAdapters) {
if (adapter.supports(handler)) {
return adapter;
}
}
}
throw new ServletException("No adapter for handler [" + handler +
"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
}
|
4 前置拦截 - applyPreHandle()
源码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
public class HandlerExecutionChain {
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = 0; i < interceptors.length; i++) {
HandlerInterceptor interceptor = interceptors[i];
// 遍历执行拦截器的前置方法,只要有一个返回了false,就返回false。
// 每次执行一个前置拦截后,就将interceptorIndex+1,当有前置方法返回false时,执行triggerAfterCompletion。
if (!interceptor.preHandle(request, response, this.handler)) {
// 倒序执行后置拦截,起始索引是 interceptorIndex,即如果也有前置拦截执行失败了,
// 那么相应的这个失败的及之后的拦截器的后置拦截就不会执行。
triggerAfterCompletion(request, response, null);
return false;
}
this.interceptorIndex = i;
}
}
return true;
}
}
|
调用执行链中的方法,遍历执行拦截器的前置拦截方法,每成功执行一个,将成员变量 interceptorIndex 的值 +1,在这之间如果前置拦截返回 false,就会跳过中置拦截,直接触发后置拦截。
也就是说,如果有任何一个前置拦截返回了 false,那么所有的中置拦截方法都不会执行。
后置拦截的执行时倒序的,并不一定是从最后一个开始,而是根据最后一个返回 true 的前置拦截的索引 interceptorIndex 开始,倒序执行到列表的开头。
后置拦截的源码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
public class HandlerExecutionChain {
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex)
throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
// 倒序执行,起始索引是最后一个返回 true 的前置拦截的索引。
for (int i = this.interceptorIndex; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
try {
interceptor.afterCompletion(request, response, this.handler, ex);
}
catch (Throwable ex2) {
logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
}
}
}
}
}
|
5 中置拦截 - applyPostHandle()
源码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
public class HandlerExecutionChain {
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
// 如果存在拦截器,倒序执行中置拦截。能执行到这个方法,说明所有的前置拦截都成功执行了。
for (int i = interceptors.length - 1; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
interceptor.postHandle(request, response, this.handler, mv);
}
}
}
}
|
中置拦截是从最后一个索引开始,倒序执行的。能执行到这里,那么所有的前置拦截一定全部返回了true。所以这里可以不用根据前面记录的索引来执行,而是直接从最后一个索引开始,倒序执行。
6 全局异常处理及后置拦截 - processDispatchResult()
源码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
public class DispatcherServlet extends FrameworkServlet {
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
@Nullable Exception exception) throws Exception {
boolean errorView = false;
// 如果前面的流程中抛出了异常,在这里会进行处理。
if (exception != null) {
if (exception instanceof ModelAndViewDefiningException) {
logger.debug("ModelAndViewDefiningException encountered", exception);
mv = ((ModelAndViewDefiningException) exception).getModelAndView();
}
else {
// TODO 异常处理
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
mv = processHandlerException(request, response, handler, exception);
errorView = (mv != null);
}
}
// 省略部分代码...
if (mappedHandler != null) {
// 执行后置拦截
mappedHandler.triggerAfterCompletion(request, response, null);
}
}
}
|
在外围方法中,是捕获了具体方法执行过程中,抛出的异常的。
如果业务方法中抛出了异常,则会作为参数传递到这里。如果存在异常,就会调用全局异常处理。
最后执行后置拦截。
异常处理也是通过策略模式实现,在接口 HandlerExceptionResolver 中,只定义了 resolveException(),而在其抽象子类中定义了 shouldApplyTo(),这个方法判断了当前的异常处理类是否支持指定的异常。
遍历所有的异常处理实例,首先判断是否支持,如果支持处理当前异常,就会调用 doResolveHandlerMethodException()。
doResolveHandlerMethodException() 大体分为两步,首先获取异常处理方法对象,然后执行异常处理方法。
源码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExceptionResolver
implements ApplicationContextAware, InitializingBean {
protected ModelAndView doResolveHandlerMethodException(HttpServletRequest request,
HttpServletResponse response, @Nullable HandlerMethod handlerMethod, Exception exception) {
// TODO 获取异常处理方法
ServletInvocableHandlerMethod exceptionHandlerMethod = getExceptionHandlerMethod(handlerMethod, exception);
if (exceptionHandlerMethod == null) {
return null;
}
// 设置参数解析器和返回值处理器
if (this.argumentResolvers != null) {
exceptionHandlerMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
if (this.returnValueHandlers != null) {
exceptionHandlerMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
}
// 省略部分代码...
Throwable cause = exception.getCause();
if (cause != null) {
// 异常处理方法的执行。
// Expose cause as provided argument as well
exceptionHandlerMethod.invokeAndHandle(webRequest, mavContainer, exception, cause, handlerMethod);
}
// 省略部分代码...
}
}
|
ServletInvocableHandlerMethod 的获取源码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExceptionResolver
implements ApplicationContextAware, InitializingBean {
protected ServletInvocableHandlerMethod getExceptionHandlerMethod(
@Nullable HandlerMethod handlerMethod, Exception exception) {
Class<?> handlerType = null;
// 获取异常处理方法,这里使用了缓存,也就是只会查找一次。
if (handlerMethod != null) {
// Local exception handler methods on the controller class itself.
// To be invoked through the proxy, even in case of an interface-based proxy.
handlerType = handlerMethod.getBeanType();
ExceptionHandlerMethodResolver resolver = this.exceptionHandlerCache.get(handlerType);
if (resolver == null) {
// ExceptionHandlerMethodResolver定义了对注解@ExceptionHandler的支持
// 查找@ControllerAdvice标注的处理类中,标注有 @ExceptionHandler 的方法,并将注解中配置的 Exception类型与方法的反射对象
// 映射关系封装缓存起来。如果一个controller中抛出了异常,就可以根据这个异常从异常处理类中找到这个处理方法了。
resolver = new ExceptionHandlerMethodResolver(handlerType);
this.exceptionHandlerCache.put(handlerType, resolver);
}
Method method = resolver.resolveMethod(exception);
if (method != null) {
return new ServletInvocableHandlerMethod(handlerMethod.getBean(), method);
}
// For advice applicability check below (involving base packages, assignable types
// and annotation presence), use target class instead of interface-based proxy.
if (Proxy.isProxyClass(handlerType)) {
handlerType = AopUtils.getTargetClass(handlerMethod.getBean());
}
}
// 省略部分代码...
return null;
}
}
|
如上源码,这里用到了缓存。第一次执行时,会创建一个 ExceptionHandlerMethodResolver。
ExceptionHandlerMethodResolver 构造函数中,就会查找异常处理类中所有带有 @ExceptionHandler 的方法。
源码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
public class ExceptionHandlerMethodResolver {
public static final MethodFilter EXCEPTION_HANDLER_METHODS = method ->
AnnotatedElementUtils.hasAnnotation(method, ExceptionHandler.class);
public ExceptionHandlerMethodResolver(Class<?> handlerType) {
// 使用反射查找处理类中的所有带有 @ExceptionHandler 注解的方法。
for (Method method : MethodIntrospector.selectMethods(handlerType, EXCEPTION_HANDLER_METHODS)) {
for (Class<? extends Throwable> exceptionType : detectExceptionMappings(method)) {
addExceptionMapping(exceptionType, method);
}
}
}
}
|
异常的处理逻辑源码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
public class ServletInvocableHandlerMethod extends InvocableHandlerMethod {
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// TODO 重点:具体方法调用逻辑
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
// 省略部分代码...
// TODO 使用返回值处理器,对返回值进行处理
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
// 省略部分代码...
}
}
|
首先反射调用异常处理方法,然后调用返回值处理。
反射调用逻辑:
1
2
3
4
5
6
7
8
9
10
|
public class InvocableHandlerMethod extends HandlerMethod {
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// TODO 重点:获取参数数组
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
// TODO 方法的反射执行
return doInvoke(args);
}
}
|
handleReturnValue() 中会处理返回值。比如有页面跳转、json数据流的响应,他们的处理方式是不一样的。通过策略模式,选择合适的处理类进行处理。
源码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
public class HandlerMethodReturnValueHandlerComposite implements HandlerMethodReturnValueHandler {
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
// TODO 查找返回值处理器,策略模式的一种运用
HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
// 如果不存在返回值处理器,则跑出异常
if (handler == null) {
throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
}
// 对返回值进行处理
handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}
}
|
处理类的选择源码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
public class HandlerMethodReturnValueHandlerComposite implements HandlerMethodReturnValueHandler {
private HandlerMethodReturnValueHandler selectHandler(@Nullable Object value, MethodParameter returnType) {
boolean isAsyncValue = isAsyncReturnValue(value, returnType);
// 遍历容器中所有的返回值处理器,判断是否支持,如果有返回值处理器支持这个返回值,则返回此处理器。
// 这也是策略模式的一种运用。
for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {
if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) {
continue;
}
if (handler.supportsReturnType(returnType)) {
return handler;
}
}
return null;
}
}
|
与之前流程中用到的策略模式,一样的套路。
判断是否支持处理对应的返回值,如果支持,就调用对应的 handleReturnValue()。