网易建站模板,一键logo,多用户商城网站开发,青岛品牌网站建设价格接上一遍博客《SpringMVC源码深度解析(上)》继续聊。最后聊到了SpringMVC的九大组建的初始化#xff0c;以 HandlerMapping为例#xff0c;SpringMVC提供了三个实现了#xff0c;分别是#xff1a;BeanNameUrlHandlerMapping、RequestMappingHandlerMapping、RouterFunctio… 接上一遍博客《SpringMVC源码深度解析(上)》继续聊。最后聊到了SpringMVC的九大组建的初始化以 HandlerMapping为例SpringMVC提供了三个实现了分别是BeanNameUrlHandlerMapping、RequestMappingHandlerMapping、RouterFunctionMapping其中最常用的就是 RequestMappingHandlerMapping与RequestMapping注解相关以它为例先看看类的继承图 可知该类实现了InitializingBean接口这是Spring的扩展点Bean对象在初始化的时候会调用 RequestMappingHandlerMapping#afterPropertiesSet()方法。如果使用EnableWebMvc注解或者手动往Spring容器中注入 RequestMappingHandlerMapping对象Web容器在调用refresh()方法的过程中会调用afterPropertiesSet()方法如果不是通过以上两种方式的话由上一篇博客 《SpringMVC源码深度解析(上)》可知会读取dispatcherservlet.properties文件获取默认的HandlerMapping的实现类但是由于在前面已经调用了Web容器的refresh()方法完成了容器的刷新因此这里需要特殊处理代码如下 可知这里会显示的调用AutowireCapableBeanFactory#createBean()方法才会经历Bean的实例化与初始化才会调用 InitializingBean#afterPropertiesSet()方法。我专门提到这个方法也侧面说明这个方法很重要看看这个方法代码如下 重点看看AbstractHandlerMethodMapping#getMappingForMethod()方法代码如下 再看看AbstractHandlerMethodMapping#registerHandlerMethod()方法代码如下 到这里为止就可以知道RequestMappingHandlerMapping在初始化的时候就会获取到所有被Controller/RequestMapping注解修饰的类并且得到该类中所有被Requestmapping注解修饰的方法每个被RequestMapping注解修饰的方法最终生成一个对应的HandlerMethod对象(存储被Controller/RequestMapping注解修饰的对象和被RequestMapping注解修饰的方法)并存储在内部类RequestMappingHandlerMapping.MappingRegistry的registry(Map)属性中key为RequestMappingInfo对象value为MappingRegistration对象(存储HandlerMethod对象)。 聊完了RequestMappingHandlerMapping在初始化再聊聊SpringMVC是如何处理请求。其实就是要搞清楚DispatcherServlet的原理它是一个Servlet在《SpringMVC源码深度解析(上)》中也说到了创建了DispatcherServlet对象后会添加到Servlet容器中。如果有请求来了会解析url并匹配如果是符合DispatcherServlet的匹配路径则调用 GenericServlet#service()方法这是一个抽象方法因此实际调用的是HttpServlet#service()方法代码如下 以POST请求为例则调用的是HttpServlet#doPost()方法代码如下 其实对于DispatcherServlet来讲不管是哪种请求最终都是调用FrameworkServlet#processRequest()方法代码如下 DispatcherServlet#doDispatch()方法是处理请求的核心会重点讲代码如下 在AbstractHandlerMethodMapping#lookupHandlerMethod()方法中主要是进行路径的匹配由于在前面RequestMappingInfoHandlerMapping初始化的时候已经存储好了所有的匹配路径及其HandlerMethod存放在 RequestMappingInfoHandlerMapping.MappingRegistry的pathLookup属性中因此如果满足匹配要求是可以获取到HandlerMethod对象的这块就说了涉及到匹配逻辑比较复杂感兴趣可以自己研究。回到AbstractHandlerMapping#getHandler()方法中看看AbstractHandlerMapping#getHandlerExecutionChain()方法代码如下 可知这这个方法中就是创建HandlerExecutionChain对象并将HandlerInterceptor设置到HandlerExecutionChain对象的interceptorList属性中。再回到DispatcherServlet#doDispatch()方法中代码如下 因此返回的HandlerAdapter对象是RequestMappingHandlerAdapter这里当用到的是适配器设计模式为什么要做适配呢还记得之前HandlerMapping由三个实现类的实际上处理的是三种不同的Controller因此需要有对应的适配器处理不同的情况看看HandlerAdapter#handle()方法就知道了具体如下 主要是处理这三种情况 ① 一种是被Controller/RestController/RequestMapping注解修饰的类 ② 实现了HttpRequestHandler接口的类 ③ 实现了Controller接口的类 这三种情况的类都属于Controller因此需要不同的适配器处理我主要讲①剩下的两种有兴趣可以试试。回到DispatcherServlet#doDispatch()方法继续往下看代码如下 执行拦截器的前置方法就是遍历HandlerExecutionChain的interceptorList属性执行HandlerInterceptor#preHandle()方法代码如下 执行拦截器的后置方法也是如此代码如下 当然如果执行某个拦截器的前置方法返回的是 false则直接return不往下走了。在执行拦截器的前置方法后后置方法前会执行HandlerAdapter#handle()方法代码如下 顺便说一下RequestMappingHandlerAdapter也实现了InitializingBean接口因此也会实现afterPropertiesSet()方法代码如下 这里设置的这些默认处理器后续会用到包括参数的解析、绑定、返回值的处理等。 再看看 RequestMappingHandlerAdapter#invokeAndHandle()方法这里是执行目标类中目标方法的关键代码如下 以PathVariableMethodArgumentResolver为例看看代码如下 回到InvocableHandlerMethod#getMethodArgumentValues()方法看看是如何解析参数的主要看HandlerMethodArgumentResolverComposite#resolveArgument()方法代码如下 还是以PathVariableMethodArgumentResolver看看它的resolveArgument()方法代码如下 POST请求为http://127.0.0.1:9000/hello/sayHello/张三 最后将解析获取到的参数值放入Request的Attribute中。当然除了这个之外常用的是在请求体中会放入Json数据最后参数中接受的是一个对象SpringMVC是怎么对Json格式的数据进行处理的呢这里是通过RequestResponseBodyMethodProcessor处理的代码如下 一共有八个转换器这是在哪里添加的呢后面讲EnableWebMvc注解的时候会讲到再看看HttpMessageConverter#read()方法代码如下 到这里可以知道接收的Java对象必须有Setter方法因为这里是直接通过反射调用Setter方法进行赋值的。到这个为止完成了Json的解析以及对象的赋值即下图 还有一些其他的注解比如RequestParam感兴趣的自己研究。InvocableHandlerMethod#invokeForRequest()参数处理完了再调用InvocableHandlerMethod#doInvoke()方法代码如下 反射调用玩目标方法后会有返回值也需要处理返回值。回到ServletInvocableHandlerMethod#invokeAndHandle()方法代码如下 由于返回的是对象因此需要处理由于HelloController上添加的是RestController这个注解相当于ControllerResponseBody因此最终讲返回的对象反序列化为Json格式的数据并返回给前端。这里还是需要看RequestResponseBodyMethodProcessor#handleReturnValue()方法代码如下 该方法较长我只截取重点讲。 到这里为止把返回的对象进行序列化只是将其转成字符并缓存起来回到ObjectWriter#writeValue()方法代码如下 到这里为止SpringMVC的返回值处理讲完了SpringMVC剩下的内容将在下一篇博文中讲敬请期待~