点击上方 Java后端,选择 设为星标
优质文章,及时送达
Spring MVC的工作流程
<servlet>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
</servlet>
由此得知,该请求该由哪个Controller来处理。
5. DispatcherServlet将结果响应给用户。
HandlerMapping是一个接口,这个接口返回的是一个请求访问时处理器映射器会返回具体的执行链(HandlerExecutionChain),其中包括拦截器和映射器,只是找到并不执行。
执行链这里用到了设计模式中的责任链模式,每一个责任链的负责人只需要把自己的任务处理好就好。
而HandlerMapping为什么是个接口呢,是因为 Spring MVC提供了三种不同的书写处理器映射器的方法,只不过我们最常用的是通过注解,通过@Controller
,@RequestMapping
的方式去写我们的Controller。
HandlerAdapter:
HandlerAdapter 的意思的是适配器,用到的也是设计模式中的适配器模式,在 Spring MVC 中针对不同的 Handler 需要不同的适配器,例如对于@RequestMapping
类型的 Handler 需要 RequestMappingHandlerAdapter 来处理,适配之后通过调用接口的 handle 方法就可以执行对应的方法了。
代码实现
流程设计
(由于功能比较简单另外没有实现 Interceptor 拦截器的功能,所以没有使用 Spring MVC 使用的执行链的形式)
3. 找到方法后就该执行了,但是执行前,方法需要的参数我们还没有填充。
@RequestParam
修饰的基本数据类型,有数组,有Map,有对象等等。
@ResponseBody
或者
@RestController
修饰的直接返回给前端一个JSON形式的串。
这里很简单,其实就是根据不同的情况调用 Servlet 给我们提供的方法。
流程图
代码结构
HandleMapping
@Controller
,
@RequestMapping
修饰的类和方法,以
@RequestMapping
的值作为key,以 Method 作为 value,初始化一个map。第二个就是根据 key 在刚才初始化的map中获取对应的 Method。
public class HandleMapping {
private static final Map<String, HandlerMethod> mappings = new HashMap<>();
public static void init() {
Set<Class<?>> controllerSet = ReflectionUtils.getAllClass(Controller.class);
controllerSet.forEach((controller) -> {
RequestMapping requestMappingAnnotation = controller.getAnnotation(RequestMapping.class);
if (requestMappingAnnotation == null) {
throw new DumpException("controller '" + controller.getName() + "' must have a '@RequestMapping' annotation");
}
String parentPath = requestMappingAnnotation.value();
Method[] methods = controller.getMethods();
for (Method method : methods) {
RequestMapping methodRequestMappingAnnotation = method.getAnnotation(RequestMapping.class);
if (methodRequestMappingAnnotation == null) {
continue;
}
String path = methodRequestMappingAnnotation.value();
try {
mappings.put(parentPath + path, new HandlerMethod(controller.newInstance(), method));
} catch (Exception e) {
throw new DumpException("init controller failed,can not create instance for controller '" + controller.getName() + "'", e);
}
}
});
}
public static HandlerMethod getHandler(String url) {
HandlerMethod handleMethod = mappings.get(url);
if (handleMethod == null) {
throw new DumpException("path '" + url + "' can not find handle");
}
return handleMethod;
}
}
HandlerMethodArgumentResolver
public interface HandlerMethodArgumentResolver {
Boolean support(Parameter parameter);
Object resolveArgument(HttpServletRequest request, Class<?> requiredType, Parameter parameter);
}
@RequestParam
的基本数据类型的参数解析器 RequestParamResolver,一种是对象类型的参数解析器 RequestModelResolver。这里和Spring mvc不同,因为我暂时只实现了这两种,而对于Map,数组等形式的都暂不支持。为了方便识别对象,我规定需要解析参数的对象都需要用
@RequestModel
来修饰。
HandleMethodAdapter
1. 方法用了@ResponseBody
修饰。
response.getWriter().print()
来将返回值写入 response 中。
2. 方法没用@ResponseBody
修饰,返回值含有redirect:
前缀。
这代表该请求是一个重定向请求,这里用response.sendRedirect()
将请求重定向。
3. 方法没用@ResponseBody
修饰,返回值也不含有redirect:
前缀。
requestDispatcher.forward()
即可。
DumpServletDispatcher
public class DumpServletDispatcher extends HttpServlet {
@Override
public final void init() {
HandleMapping.init();
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String uri = req.getRequestURI();
HandlerMethod handleMethod = HandleMapping.getHandler(uri);
HandleMethodAdapter handleMethodAdapter = new HandleMethodAdapter();
handleMethodAdapter.handle(req, resp, handleMethod);
}
}
最后
本文作者「袁广鑫」,欢迎关注作者的知乎:
https://zhuanlan.zhihu.com/p/139751932 专注于 Java 技术分享,点击阅读原文即可关注。
如果看到这里,说明你喜欢这篇文章,请 转发、点赞。同时 标星(置顶)本公众号可以第一时间接受到博文推送。
推荐阅读
1. 2020 年 5 月全国程序员工资出炉!
2. 使用 Docker 部署 Spring Cloud 项目详细步骤
3. 一行命令下载全网视频
4. 彻底理解 SpringIOC、DI
《Java技术栈学习手册》
,覆盖了Java技术、面试题精选、Spring全家桶、Nginx、SSM、微服务、数据库、数据结构、架构等等。
获取方式:点“ 在看,关注公众号 Java后端 并回复 777 领取,更多内容陆续奉上。
喜欢文章,点个在看
本文分享自微信公众号 - Java后端(web_resource)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。