SpringBootWeb开发-2-2
上一级页面:ssm-spring-boot速成学习索引
前言
本节描述,一个请求发送到DispatcherServlet后的具体处理流程,也就是SpringMVC的主要原理。
本节内容较多且硬核,对日后编程很有帮助,需耐心对待。
本节第一遍有一个耳熟,有大致印象即可,不明白就再听一遍本节,循环往复,直到听明白。
听明白后,一定要课后复盘一次,自己用IDE调试走完一遍流程。
名词解释
debug工具中有许多专有名词,它们需要记忆,以方便理解其他程序员调试的时候到底在说什么。
![Pasted image 20230125102332.png](https://webdav-1309345210.file.myqcloud.com/images/Pasted image 20230125102332.png)
图中红框按钮,从左到右依次是
- step-over 步过:即在单步执行时,在函数内遇到子函数时不会进入子函数内单步执行,而是将子函数整个执行完再停止,也就是把子函数整个作为一步。
- step-into 步入:单步执行,遇到子函数就进入并且继续单步执行。
- step-out 步出:当单步执行到子函数内时,在子函数内,使用step out就可以执行完子函数余下部分,并返回到返回到上一层函数(即调用此子函数的函数)。
- run-to-cursor 程序运行,并跳转到鼠标指针处 在JB系中,还有这个按钮 ![Pasted image 20230125102917.png](https://webdav-1309345210.file.myqcloud.com/images/Pasted image 20230125102917.png) recover-run,恢复程序运行:在当前位置顺序执行程序,执行过程中遇到断点则停留在断点。未遇到断点则恢复程序正常运行
32、请求处理-【源码分析】-各种类型参数解析原理
这要从DispatcherServlet
类的doDispatch
方法开始:
public class DispatcherServlet extends FrameworkServlet {
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
...
先看这句:
mappedHandler = getHandler(processedRequest);
步入进去
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
for (HandlerMapping mapping : this.handlerMappings) {
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
HandlerMapping
中找到能处理请求的Handler
(即XXXController.XXXmethod()
)。
步过,跳回到DispatcherServlet
类的doDispatch
方法,
注意这句:
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
步入getHandlerAdapter
方法,发现
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
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");
}
- 为当前Handler 找一个适配器
HandlerAdapter
,
步过,跳回到DispatcherServlet
类的doDispatch
方法,
注意到这句
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
- 适配器执行目标方法并确定方法参数的每一个值。
这个方法的详细解析在下一节。
小结:
HandlerMapping
中找到能处理请求的Handler
(即XXXController.XXXmethod()
)。- 为当前Handler 找一个适配器
HandlerAdapter
(实际上用的最多的是RequestMappingHandlerAdapter。) - 适配器执行目标方法并确定方法参数的每一个值。
HandlerAdapter和RequestMappingHandlerAdapter
Spring的设计思想之一:适配器模式(Adapter mode)
上一小节说到,
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
步入getHandlerAdapter
方法,发现
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
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");
}
注意到this.handlerAdapters
,在DispatcherServlet
类中搜索handlerAdapters
,发现SpringBoot默认会加载所有HandlerAdapter
,大致流程如下:
找到handlerAdapters
的初始化方法
protected void initStrategies(ApplicationContext context) {
// ...
initHandlerAdapters(context);
// ...
}
Ctrl+左键,点击进入initHandlerAdapters(context);
来到DispatcherServlet
类的initHandlerAdapters
方法
public class DispatcherServlet extends FrameworkServlet {
/** Detect all HandlerAdapters or just expect "handlerAdapter" bean?. */
private boolean detectAllHandlerAdapters = true;
//...
private void initHandlerAdapters(ApplicationContext context) {
this.handlerAdapters = null;
if (this.detectAllHandlerAdapters) {
// Find all HandlerAdapters in the ApplicationContext, including ancestor contexts.
Map<String, HandlerAdapter> matchingBeans =BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerAdapters = new ArrayList<>(matchingBeans.values());
// We keep HandlerAdapters in sorted order.
AnnotationAwareOrderComparator.sort(this.handlerAdapters);
}
}
...
在这个方法中打断点调试一下,
![Pasted image 20230125101353.png](https://webdav-1309345210.file.myqcloud.com/images/Pasted image 20230125101353.png)
方法执行后,查看this.handlerAdapters
发现有这些HandlerAdapter
:
0
:支持方法上标注@RequestMapping
1
:支持函数式编程的2
:….3
:….
其中最常用的是0
:RequestMappingHandlerAdapter
执行目标方法 ha.handle(processedRequest, response, mappedHandler.getHandler())
回到DispatcherServlet
类的doDispatch
方法
public class DispatcherServlet extends FrameworkServlet {
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
ModelAndView mv = null;
...
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
...
//本节重点
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
注意到关键语句,来到本篇文章的解析重点:
//本节重点
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
步入进去,来到:
@Override
@Nullable
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return handleInternal(request, response, (HandlerMethod) handler);
}
继续步入,来到RequestMappingHandlerAdapter
类的handleInternal
方法
RequestMappingHandlerAdapter
类实现了接口HandlerAdapter
RequestMappingHandlerAdapter
主要用来处理@RequestMapping
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
implements BeanFactoryAware, InitializingBean {
// handleInternal方法
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ModelAndView mav;
checkRequest(request);
// Execute invokeHandlerMethod in synchronized block if required.
if (this.synchronizeOnSession) {
// ...
}
else {
// No HttpSession available -> no mutex necessary
mav = invokeHandlerMethod(request, response, handlerMethod);
}
// ...
}
}
关键在这一行
//handleInternal的核心
mav = invokeHandlerMethod(request, response, handlerMethod);//解释看下节
步入进去,来到核心内容:invokeHandlerMethod
方法
参数解析器 argumentResolvers
核心方法supportsParameter
和resolveArgument
RequestMappingHandlerAdapter
类的invokeHandlerMethod
方法,里面有一个参数解析器 argumentResolvers
@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
// 注意这里
//<-----关注点
if (this.argumentResolvers != null) {
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
...
注意图中红框标记位置
![Pasted image 20230124204030.png](https://webdav-1309345210.file.myqcloud.com/images/Pasted image 20230124204030.png)
前面都是一些初始化相关的语句,来到关键语句:
if (this.argumentResolvers != null) {
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
参数解析器确定将要执行的目标方法的每一个参数的值是什么;
评估表达式,得到结果:
![Pasted image 20230124204504.png](https://webdav-1309345210.file.myqcloud.com/images/Pasted image 20230124204504.png)
发现Spring MVC加载了大量的参数解析器argumentResolvers
- SpringMVC目标方法能写多少种参数类型。取决于参数解析器argumentResolvers。
按住Ctrl,点击this.argumentResolvers
,发现它是HandlerMethodArgumentResolverComposite
类型的
![Pasted image 20230124205025.png](https://webdav-1309345210.file.myqcloud.com/images/Pasted image 20230124205025.png)
查看这个类HandlerMethodArgumentResolverComposite
,发现它实现接口HandlerMethodArgumentResolver
![Pasted image 20230124205318.png](https://webdav-1309345210.file.myqcloud.com/images/Pasted image 20230124205318.png)
查看接口HandlerMethodArgumentResolver
,在接口中,按Ctrl+F12:
![Pasted image 20230124205406.png](https://webdav-1309345210.file.myqcloud.com/images/Pasted image 20230124205406.png)
这里是Spring的参数解析器核心设计,是本篇内容的核心点,后面的解析都紧扣这两个方法:
boolean supportsParameter(MethodParameter parameter);
当前解析器是否支持解析传进来的这种参数Object resolveArgument();
支持就调用这个方法进行解析,不支持就返回false
argumentResolvers
的初始化过程
通过双击调试栈的栈顶元素,回到RequestMappingHandlerAdapter
类,
![Pasted image 20230125105056.png](https://webdav-1309345210.file.myqcloud.com/images/Pasted image 20230125105056.png)
在RequestMappingHandlerAdapter
类中搜索argumentResolvers
,
查找argumentResolvers
的初始化过程,发现this.argumentResolvers
在afterPropertiesSet()
方法内初始化
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
implements BeanFactoryAware, InitializingBean {
@Nullable
private HandlerMethodArgumentResolverComposite argumentResolvers;
@Override
public void afterPropertiesSet() {
...
if (this.argumentResolvers == null) {//初始化argumentResolvers
List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
...
}
getDefaultArgumentResolvers
方法
通过Ctrl+点击,查看getDefaultArgumentResolvers
方法。
发现这个方法初始化了一堆的实现HandlerMethodArgumentResolver
接口的参数解析器ArgumentResolver
//初始化了一堆的实现HandlerMethodArgumentResolver接口的参数解析器ArgumentResolver
private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>(30);
// Annotation-based argument resolution
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
resolvers.add(new RequestParamMapMethodArgumentResolver());
resolvers.add(new PathVariableMethodArgumentResolver());
resolvers.add(new PathVariableMapMethodArgumentResolver());
resolvers.add(new MatrixVariableMethodArgumentResolver());
resolvers.add(new MatrixVariableMapMethodArgumentResolver());
resolvers.add(new ServletModelAttributeMethodProcessor(false));
resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters(), this.requestResponseBodyAdvice));
resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));
resolvers.add(new RequestHeaderMapMethodArgumentResolver());
resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));
resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
resolvers.add(new SessionAttributeMethodArgumentResolver());
resolvers.add(new RequestAttributeMethodArgumentResolver());
// Type-based argument resolution
resolvers.add(new ServletRequestMethodArgumentResolver());
resolvers.add(new ServletResponseMethodArgumentResolver());
resolvers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
resolvers.add(new RedirectAttributesMethodArgumentResolver());
resolvers.add(new ModelMethodProcessor());
resolvers.add(new MapMethodProcessor());
resolvers.add(new ErrorsMethodArgumentResolver());
resolvers.add(new SessionStatusMethodArgumentResolver());
resolvers.add(new UriComponentsBuilderMethodArgumentResolver());
if (KotlinDetector.isKotlinPresent()) {
resolvers.add(new ContinuationHandlerMethodArgumentResolver());
}
// Custom arguments
if (getCustomArgumentResolvers() != null) {
resolvers.addAll(getCustomArgumentResolvers());
}
// Catch-all
resolvers.add(new PrincipalMethodArgumentResolver());
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
resolvers.add(new ServletModelAttributeMethodProcessor(true));
return resolvers;
}
}
HandlerMethodArgumentResolverComposite
回到afterPropertiesSet()
方法
public void afterPropertiesSet() {
// Do this first, it may add ResponseBody advice beans
initControllerAdviceCache();
initMessageConverters();
if (this.argumentResolvers == null) {
List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
if (this.initBinderArgumentResolvers == null) {
List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
if (this.returnValueHandlers == null) {
List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
}
}
注意到HandlerMethodArgumentResolverComposite
类
这个类是众多参数解析器argumentResolvers的包装类
,
- 对于包装类,一般包装单个的命名为warpper。包装多个的命名为Composite
内容大致如下:
public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgumentResolver {
private final List<HandlerMethodArgumentResolver> argumentResolvers = new ArrayList<>();
...
public HandlerMethodArgumentResolverComposite addResolvers(
@Nullable HandlerMethodArgumentResolver... resolvers) {
if (resolvers != null) {
Collections.addAll(this.argumentResolvers, resolvers);
}
return this;
}
...
}
类HandlerMethodArgumentResolverComposite
实现了接口HandlerMethodArgumentResolver
接口HandlerMethodArgumentResolver
源码大致如下:
public interface HandlerMethodArgumentResolver {
//当前解析器是否支持解析这种参数
boolean supportsParameter(MethodParameter parameter);
@Nullable//如果支持,就调用 resolveArgument
Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;
}
返回值处理器 ReturnValueHandler
类似于上一节对参数解析器的调试分析过程,对返回值处理器ReturnValueHandler做解析:
点击栈顶元素,回到RequestMappingHandlerAdapter
类的invokeHandlerMethod
方法
@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
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);
}
...
注意到
if (this.returnValueHandlers != null) {//<---关注点
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
}
通过类似的搜索方法,发现this.returnValueHandlers
在afterPropertiesSet()
方法内初始化
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
implements BeanFactoryAware, InitializingBean {
@Nullable
private HandlerMethodReturnValueHandlerComposite returnValueHandlers;
@Override
public void afterPropertiesSet() {
...
if (this.returnValueHandlers == null) {
List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
}
}
查看getDefaultReturnValueHandlers
方法
//初始化了一堆的实现HandlerMethodReturnValueHandler接口的
private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {
List<HandlerMethodReturnValueHandler> handlers = new ArrayList<>(20);
// Single-purpose return value types
handlers.add(new ModelAndViewMethodReturnValueHandler());
handlers.add(new ModelMethodProcessor());
handlers.add(new ViewMethodReturnValueHandler());
handlers.add(new ResponseBodyEmitterReturnValueHandler(getMessageConverters(),
this.reactiveAdapterRegistry, this.taskExecutor, this.contentNegotiationManager));
handlers.add(new StreamingResponseBodyReturnValueHandler());
handlers.add(new HttpEntityMethodProcessor(getMessageConverters(),
this.contentNegotiationManager, this.requestResponseBodyAdvice));
handlers.add(new HttpHeadersReturnValueHandler());
handlers.add(new CallableMethodReturnValueHandler());
handlers.add(new DeferredResultMethodReturnValueHandler());
handlers.add(new AsyncTaskMethodReturnValueHandler(this.beanFactory));
// Annotation-based return value types
handlers.add(new ServletModelAttributeMethodProcessor(false));
handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(),
this.contentNegotiationManager, this.requestResponseBodyAdvice));
// Multi-purpose return value types
handlers.add(new ViewNameMethodReturnValueHandler());
handlers.add(new MapMethodProcessor());
// Custom return value types
if (getCustomReturnValueHandlers() != null) {
handlers.addAll(getCustomReturnValueHandlers());
}
// Catch-all
if (!CollectionUtils.isEmpty(getModelAndViewResolvers())) {
handlers.add(new ModelAndViewResolverMethodReturnValueHandler(getModelAndViewResolvers()));
}
else {
handlers.add(new ServletModelAttributeMethodProcessor(true));
}
return handlers;
}
}
查看HandlerMethodReturnValueHandlerComposite
类,如下:
public class HandlerMethodReturnValueHandlerComposite implements HandlerMethodReturnValueHandler {
private final List<HandlerMethodReturnValueHandler> returnValueHandlers = new ArrayList<>();
...
public HandlerMethodReturnValueHandlerComposite addHandlers(
@Nullable List<? extends HandlerMethodReturnValueHandler> handlers) {
if (handlers != null) {
this.returnValueHandlers.addAll(handlers);
}
return this;
}
}
注意到实现了HandlerMethodReturnValueHandler
接口:
public interface HandlerMethodReturnValueHandler {
boolean supportsReturnType(MethodParameter returnType);
void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception;
}
定位到真正执行目标方法 doInvoke(args)
结束之前的调试,
重新开始调试,从DispatcherServlet
类的doDispatch
方法开始,在这打个断点
public class DispatcherServlet extends FrameworkServlet {
...
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
ModelAndView mv = null;
...
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
发现关键的执行目标方法语句:
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
步入ha.handle()
,来到RequestMappingHandlerAdapter
的handle()
方法:
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return handleInternal(request, response, (HandlerMethod) handler);
}
继续步入,来到类RequestMappingHandlerAdapter
的handleInternal
方法
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
implements BeanFactoryAware, InitializingBean {
//...
@Override
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ModelAndView mav;
// ...
//handleInternal的核心
mav = invokeHandlerMethod(request, response, handlerMethod);//解释看下节
// ...
return mav;
}
}
发现核心的执行方法
//handleInternal的核心
mav = invokeHandlerMethod(request, response, handlerMethod);
继续步入invokeHandlerMethod()
进去,
RequestMappingHandlerAdapter
的invokeHandlerMethod()
方法:
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 {
//...
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
if (this.argumentResolvers != null) {
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
if (this.returnValueHandlers != null) {
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
}
// ...
//关注点:执行目标方法
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
webRequest.requestCompleted();
}
}
注意到执行目标方法的语句:
//关注点:执行目标方法
invocableMethod.invokeAndHandle(webRequest, mavContainer);
步入进去invocableMethod.invokeAndHandle()
方法,
invokeAndHandle()
方法如下:
public class ServletInvocableHandlerMethod extends InvocableHandlerMethod {
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// 真正执行的方法
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
setResponseStatus(webRequest);
给这个方法内打上两个断点,
![Pasted image 20230125111212.png](https://webdav-1309345210.file.myqcloud.com/images/Pasted image 20230125111212.png)
并且给最终要执行的XXXController.XXXmethod
方法中打上一个断点,例如我自己编写的RequestController
中的bossAge
方法
![Pasted image 20230125111445.png](https://webdav-1309345210.file.myqcloud.com/images/Pasted image 20230125111445.png)
在Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
处
![Pasted image 20230125111543.png](https://webdav-1309345210.file.myqcloud.com/images/Pasted image 20230125111543.png)
按恢复程序执行
按钮,它会从当前位置开始,顺序执行程序,知道遇到下一个断点。
![Pasted image 20230125111703.png](https://webdav-1309345210.file.myqcloud.com/images/Pasted image 20230125111703.png)
结果发现跳转到最终要执行的XXXController.XXXmethod
方法。
说明这里的invokeForRequest
方法就是我们要找的真正执行目标方法。关键语句如下:
![Pasted image 20230125111932.png](https://webdav-1309345210.file.myqcloud.com/images/Pasted image 20230125111932.png)
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
步入invokeForRequest
方法,
![Pasted image 20230124212037.png](https://webdav-1309345210.file.myqcloud.com/images/Pasted image 20230124212037.png)
发现两个关键语句
//下一小节解析这个
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
// 这一小节继续解析这个
return doInvoke(args);
步入doInvoke
,来到doInvoke
方法
![Pasted image 20230124212448.png](https://webdav-1309345210.file.myqcloud.com/images/Pasted image 20230124212448.png)
已经开始调用反射工具类了,说明这里已经到达业务逻辑的最底层了
总结:通过本小节的内容,一步一步使用IDE的断点调试工具,找到了框架最底层调用反射工具类的方法。找到了真正的执行方法doInvoke
方法
定位到ServletInvocableHandlerMethod
类的getMethodArgumentValues
方法
先结束上面的调试。
重新开始调试,遵循上一小节的步骤,来到invokeForRequest()
方法
![Pasted image 20230125112307.png](https://webdav-1309345210.file.myqcloud.com/images/Pasted image 20230125112307.png)
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// 这一小节解析的内容
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
if (logger.isTraceEnabled()) {
logger.trace("Arguments: " + Arrays.toString(args));
}
return doInvoke(args);
}
注意到这里的getMethodArgumentValues
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
步入getMethodArgumentValues
方法,来到关键方法getMethodArgumentValues()
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// 使用`getMethodArgumentValues`方法确定每一个参数的值`parameters`
MethodParameter[] parameters = getMethodParameters();
if (ObjectUtils.isEmpty(parameters)) {
return EMPTY_ARGS;
}
定位到ServletInvocableHandlerMethod
类,getMethodArgumentValues
方法
获取当前请求(request)的方法参数值(Method Argument Values)getMethodArgumentValues()
分析ServletInvocableHandlerMethod
类的的getMethodArgumentValues
方法
getMethodArgumentValues()
获取当前请求request的方法参数值,检查提供的参数值。getMethodArgumentValues()
对参数进行解析,以获取其对应的值,返回的结果数组args将传递给doInvoke
方法。
Get the method argument values for the current request, checking the provided argument values and falling back to the configured argument resolvers. The resulting array will be passed into doInvoke.
例如对于url
http://localhost:8080/api/boss/001;age=34;jobs=开发,研发
通过这个方法 getMethodArgumentValues()
能够解析出来,结果args如下:
![Pasted image 20230124230425.png](https://webdav-1309345210.file.myqcloud.com/images/Pasted image 20230124230425.png)
大致源码如下:
public class ServletInvocableHandlerMethod extends InvocableHandlerMethod {
...
@Nullable//InvocableHandlerMethod类的,ServletInvocableHandlerMethod类继承InvocableHandlerMethod类
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
//本节重点,获取方法的参数值
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
MethodParameter[] parameters = getMethodParameters();
if (ObjectUtils.isEmpty(parameters)) {
return EMPTY_ARGS;
}
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;
}
//查看resolvers是否有支持
if (!this.resolvers.supportsParameter(parameter)) {
throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
}
try {
//支持的话就开始解析吧
args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
}
catch (Exception ex) {
....
}
}
return args;
}
}
其中重点语句有2个
if (!this.resolvers.supportsParameter(parameter)) {
//..
}
args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
会在接下来的小节中继续分析
遍历查找参数解析器(Argument resolver)
注意到这句:
//查看resolvers是否有支持
if (!this.resolvers.supportsParameter(parameter)) {
throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
}
- 其中
this.resolvers.supportsParameter(parameter)
是本小节的重点。 - 这个函数的目标是找到,支持解析对应参数的参数值解析器(Argument Values resolver)
首先评估表达式this.resolvers
,发现this.resolvers
的类型为HandlerMethodArgumentResolverComposite
(在参数解析器 argumentResolvers章节提及)
现在,步入this.resolvers.supportsParameter
,来到HandlerMethodArgumentResolverComposite
类的supportsParameter
方法。
@Override
public boolean supportsParameter(MethodParameter parameter) {
return getArgumentResolver(parameter) != null;
}
继续步入,来到方法getArgumentResolver
@Nullable
private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
if (result == null) {
//挨个判断所有参数解析器那个支持解析这个参数
for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) {
if (resolver.supportsParameter(parameter)) {
result = resolver;
//找到了,resolver就缓存起来,方便稍后resolveArgument()方法使用
this.argumentResolverCache.put(parameter, result);
break;
}
}
}
return result;
}
注意到这个增强for循环,是关键语句
//挨个判断所有参数解析器那个支持解析这个参数
for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) {
if (resolver.supportsParameter(parameter)) {
result = resolver;
//找到了,resolver就缓存起来,方便稍后resolveArgument()方法使用
this.argumentResolverCache.put(parameter, result);
break;
}
}
- 遍历判断参数解析器(resolver),找到支持解析这个参数的参数解析器(resolver)
- 找到了先缓存起来,
- 返回找到的结果result
解析流程--使用参数解析器(Argument resolver)进行解析
步出,回到方法getMethodArgumentValues
:
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// ...
args[i] = findProvidedArgument(parameter, providedArgs);
if (args[i] != null) {
continue;
}
if (!this.resolvers.supportsParameter(parameter)) {
throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
}
try {
// 注意这里解析参数的值
args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
}
注意到语句
args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
步入进去:
来到HandlerMethodArgumentResolverComposite
类的resolveArgument
方法
@Override
@Nullable
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
if (resolver == null) {
throw new IllegalArgumentException("Unsupported parameter type [" +
parameter.getParameterType().getName() + "]. supportsParameter should be called first.");
}
return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
}
在这里
- 首先
getArgumentResolver(parameter);
获取前文遍历得到的参数解析器argumentResolvers
- 然后
return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
使用参数解析器执行解析操作。 - 最终得到参数的值,例如下图中的”34“、“开发,研发”,都是通过参数解析器获得的参数值。
![Pasted image 20230124230425.png](https://webdav-1309345210.file.myqcloud.com/images/Pasted image 20230124230425.png)
debug来到return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
,就已经到达了业务逻辑的最底层。因为再往下深究,就是底层的工具类了。
小结
核心语句:
// 寻找哪个解析器能够解析这个参数
if (!this.resolvers.supportsParameter(parameter)) {
throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
}
try {
// 调用对应的解析器来解析这个参数
args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
}
this.resolvers.supportsParameter(parameter)
遍历获得对应的参数解析器this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory)
使用上文获得的参数解析器来解析参数,得到参数的值
本节描述,一个请求发送到DispatcherServlet后的具体处理流程,也就是SpringMVC的主要原理。
本节内容较多且硬核,对日后编程很有帮助,需耐心对待。
学习本节时,要运行一个示例,打断点,在Debug模式下,查看程序流程。
本节课的重要内容是掌握断点调试Debug。本节课演示了如果通过debug,一步一步搞清出程序的执行流程,这是本节课必须要掌握的。
本节课还在debug的过程中介绍了spring的一些设计思想,spring在代码复用等方面的写法,这些是很好的范例,要求学习和了解,在以后的工作中会有机会运用。