警告
本文最后更新于 2020-12-17,文中内容可能已过时。
spring源码系列文章,示例代码的中文注释,均是 copy 自 https://gitee.com/wlizhi/spring-framework 。
链接中源码是作者从 github 下载,并以自身理解对核心流程及主要节点做了详细的中文注释。
DispatcherServlet.doDispatch()中,具体业务方法是通过HandlerAdapter.handle()来调用的,本文性详细列举handle()的实现流程。
方法调用流程:
ha.handle() -> handleInternal() -> invokeHandlerMethod() -> invokeAndHandle() -> invokeForRequest() -> getMethodArgumentValues() ->
resolveArgument() -> getArgumentResolver() -> resolveArgument() -> doInvoke() -> invoke() -> handleReturnValue()
按照以上方法调用流程,来看源码。
invokeHandlerMethod() 源码如下:
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
|
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
implements BeanFactoryAware, InitializingBean {
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
// 获取数据绑定工厂 @InitBinder注解支持,没太多用
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
// Model工厂,收集了@ModelAttribute注解的方法
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
// 可调用的方法对象
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
if (this.argumentResolvers != null) {
// 设置参数解析器
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
if (this.returnValueHandlers != null) {
// 设置返回值解析器
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
}
// 设置参数绑定工厂
invocableMethod.setDataBinderFactory(binderFactory);
// 设置参数名称解析类
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
// 调用有@ModelAttribute注解的方法。每次请求都会调用有@ModelAttribute注解的方法
// 把@ModelAttribute注解的方法的返回值存储到 ModelAndViewContainer对象的map中了
modelFactory.initModel(webRequest, mavContainer, invocableMethod);
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
// 省略部分代码...
// TODO 重点:Controller方法调用
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
webRequest.requestCompleted();
}
}
}
|
- 首先封装 ServletWebRequest,其实句式对 request、response 实例的封装。
- 获取绑定工厂 WebDataBinderFactory,收集带有 @InitBinder 注解的方法,这个功能不常用。
- 获取 ModelFactory。收集类中没有 @RequestMapping 且有 @ModelAttribute 注解的方法,收集完成后封装到 List 中,再封装为 ModelFactory。
- 创建 ServletInvocableHandlerMethod,其实就是对handlerMethod的封装。
- 设置参数解析器,将 RequestMappingHandlerAdapter 中的 argumentResolvers,赋值给 ServletInvocableHandlerMethod。
- 设置返回值处理器,步骤同上。
- 设置绑定工厂,就是吧步骤2中获取的对象,赋值到 ServletInvocableHandlerMethod。
- 设置参数名称解析类。同步骤6。
- 调用有@ModelAttribute注解的方法。每次请求都会调用有@ModelAttribute注解的方法,把@ModelAttribute注解的方法的返回值存储到
ModelAndViewContainer对象的map中了。这也是为什么普通的接口可以引用类中 @ModelAttribute 方法的返回值作为参数,@ModelAttribute 注解的方法总是会优先执行。
- 具体业务方法的调用 invokeAndHandle()。
在执行业务方法调用时,会调用至 invokeForRequest()。
invokeForRequest() 源码如下:
1
2
3
4
5
6
7
8
9
10
11
12
|
public class InvocableHandlerMethod extends HandlerMethod {
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// TODO 重点:获取参数数组
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
if (logger.isTraceEnabled()) {
logger.trace("Arguments: " + Arrays.toString(args));
}
// TODO 方法的反射执行
return doInvoke(args);
}
}
|
共分为两步:
- 获取参数数组。
- 反射调用业务方法。
getMethodArgumentValues() 源码如下:
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 InvocableHandlerMethod extends HandlerMethod {
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
if (ObjectUtils.isEmpty(getMethodParameters())) {
return EMPTY_ARGS;
}
// 入参的包装类,里面包装了参数类型,参数名称,参数注解等等信息
MethodParameter[] parameters = getMethodParameters();
Object[] args = new Object[parameters.length];
for (int i = 0; i < parameters.length; i++) {
MethodParameter parameter = parameters[i];
// 设置参数名称解析器
parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
args[i] = findProvidedArgument(parameter, providedArgs);
if (args[i] != null) {
continue;
}
// TODO 典型的策略模式,根据parameter能否找到对应参数的处理类,能找到就返回true
// 这里遍历了所有的参数解析器,如果没有一个解析器支持此参数的解析,则抛出异常。
if (!this.resolvers.supportsParameter(parameter)) {
throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
}
// TODO 重点:具体参数值解析过程,策略模式
args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
// 省略部分代码...
}
return args;
}
}
|
resolveArgument() 源码如下:
1
2
3
4
5
6
7
8
9
10
|
public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgumentResolver {
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
// 根据参数获取对应参数的解析类,这里使用了策略模式,且使用了ConcurrentHashMap缓存
HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
// 省略非关键代码...
// 策略模式去调用具体参数解析类
return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgumentResolver {
private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
// 从缓存中获取解析器
HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
if (result == null) {
// 策略模式:循环所有的参数解析器,判断是否支持解析当前参数,如果支持,就将解析器放入缓存。
for (HandlerMethodArgumentResolver methodArgumentResolver : this.argumentResolvers) {
if (methodArgumentResolver.supportsParameter(parameter)) {
result = methodArgumentResolver;
this.argumentResolverCache.put(parameter, result);
break;
}
}
}
return result;
}
}
|
这里是典型策略模式的运用,HandlerMethodArgumentResolverComposite 中封装了容器中所有的 HandlerMethodArgumentResolver 实例,
获取到支持方法当前参数的 HandlerMethodArgumentResolver,调用 resolveArgument() 进行参数的解析。
doInvoke()源码如下:
1
2
3
4
5
6
7
8
9
10
|
public class InvocableHandlerMethod extends HandlerMethod {
protected Object doInvoke(Object... args) throws Exception {
// 将方法设置为允许访问,反射调用方法执行。
// 注意:方法的反射执行需要对象实例和参数列表。在handlerMethod封装时,并没有封装bean实例。这个bean是哪儿来的?
ReflectionUtils.makeAccessible(getBridgedMethod());
return getBridgedMethod().invoke(getBean(), args);
// 省略非关键代码...
}
}
|
这里通过方法反射调用 invoke(),对具体的业务方法进行调用。
而这里的 getBean(),仅仅返回了 this.bean。这个bean是在前面的流程 getHandler() 中进行了实例化的。
此处 getBean() 中返回的 bean,实例化的节点流程如下:
getHandler() -> getHandlerInternal() -> handlerMethod.createWithResolvedBean()
在 createWithResolvedBean() 中,调用 beanFactory.getBean() 获取了具体的实例对象。
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);
}
}
|