网站风格 颜色搭配,seo建站系统,环评在那个网站做,三星官网网站目录
SpringMVC的基本结构
1.MVC简介
2.基本结构
什么是Handler#xff1f;
什么是HandlerMapping?
什么是HandlerAdapter#xff1f;
RequestMapping方法参数解析
DispatcherServlet的init()方法
DispatcherServlet的doService()方法
SpringBoot整合SpringMVC
…目录
SpringMVC的基本结构
1.MVC简介
2.基本结构
什么是Handler
什么是HandlerMapping?
什么是HandlerAdapter
RequestMapping方法参数解析
DispatcherServlet的init()方法
DispatcherServlet的doService()方法
SpringBoot整合SpringMVC
SpringMVC执行流程图 SpringMVC的基本结构
1.MVC简介
以前的纯Servlet的处理方式
Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String type req.getParameter(Constant.REQUEST_PARAMETER_TYPE);if(type ! null !.equals(type)){if(Constant.SERVLET_TYPE_SAVE.equals(type)){// 添加用户信息try {saveOrUpdateUser(req, resp);} catch (Exception e) {e.printStackTrace();}}else if(Constant.SERVLET_TYPE_UPDATE.equals(type)){// 更新用户信息}else if(Constant.SERVLET_TYPE_DELETE.equals(type)){// 删除用户信息deleteUserById(req, resp);}else if(Constant.SERVLET_TYPE_QUEYR.equals(type)){// 查询用户queryUser(req, resp);}else if(Constant.SERVLET_TYPE_QUERYBYID.equals(type)){// 查询单条记录String id req.getParameter(id);User user userService.queryById(Integer.parseInt(id));// 跳转到更新的页面同时保存数据到Request作用域中req.setAttribute(user,user);req.getRequestDispatcher(/user/userUpdate.jsp).forward(req,resp);}else if(Constant.SERVLET_TYPE_CHECK.equals(type)){// 验证账号是否存在String userName req.getParameter(userName);String s userService.checkUserName(userName);resp.getWriter().println(s);resp.flushBuffer();}}else{// 查询用户信息queryUser(req, resp);}}
为了尽量减少依赖Servlet API提高程序的可测试性、可复用性而发展出了很多的框架技术 Struts1 Struts2 SpringMVC
2.基本结构
然后我们来看看SpringMVC的基本结构 什么是Handler
Handler表示请求处理器在SpringMVC中有四种Handler
实现了Controller接口的Bean对象实现了HttpRequestHandler接口的Bean对象添加了RequestMapping注解的方法一个HandlerFunction对象 比如实现了Controller接口的Bean对象
Component(/test)
public class MyController implements Controller {Overridepublic ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {System.out.println(hello);return new ModelAndView();}
}
实现了HttpRequestHandler接口的Bean对象
Component(/test)
public class MyController implements HttpRequestHandler {Overridepublic void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {System.out.println(hello);}
} 添加了RequestMapping注解的方法
RequestMapping
Component
public class MyController {Autowiredprivate MyService myService;RequestMapping(method RequestMethod.GET, path /test)ResponseBodypublic String test(String username) {return hello;}}
一个HandlerFunction对象以下代码中有两个
Configuration
public class AppConfig {Beanpublic RouterFunctionServerResponse person() {return route().GET(/app/person, request - ServerResponse.status(HttpStatus.OK).body(Hello GET)).POST(/app/person, request - ServerResponse.status(HttpStatus.OK).body(Hello POST)).build();}
}
什么是HandlerMapping?
HandlerMapping负责去寻找Handler并且保存路径和Handler之间的映射关系。
因为有不同类型的Handler所以在SpringMVC中会由不同的HandlerMapping来负责寻找Handler比如
BeanNameUrlHandlerMapping负责Controller接口和HttpRequestHandler接口RequestMappingHandlerMapping负责RequestMapping的方法RouterFunctionMapping负责RouterFunction以及其中的HandlerFunction
BeanNameUrlHandlerMapping的寻找流程
找出Spring容器中所有的beanName判断beanName是不是以“/”开头如果是则把它当作一个Handler并把beanName作为keybean对象作为value存入handlerMap中handlerMap就是一个Map RequestMappingHandlerMapping的寻找流程
RequestMappingHandlerMapping是在初始化方法afterPropertiesSet()中寻找的
找出Spring容器中所有beanType判断beanType是不是有Controller注解或者是不是有RequestMapping注解判断成功则继续找beanType中加了RequestMapping的Method并解析RequestMapping中的内容比如method、path封装为一个RequestMappingInfo对象把path作为keyRequestMappingInfo作为value存入pathLookup中把RequestMappingInfo对象做为keyMethod对象封装为HandlerMethod对象后作为value存入registry中
pathLookup和registry就是一个Map这样我们就能通过path找到对应的处理方法 RouterFunctionMapping的寻找流程会有些区别但是大体是差不多的相当于是一个path对应一个HandlerFunction。
各个HandlerMapping除开负责寻找Handler并记录映射关系之外自然还需要根据请求路径找到对应的Handler在源码中这三个HandlerMapping有一个共同的父类AbstractHandlerMapping AbstractHandlerMapping实现了HandlerMapping接口并实现了getHandler(HttpServletRequest request)方法。
AbstractHandlerMapping会负责调用子类的getHandlerInternal(HttpServletRequest request)方法从而找到请求对应的Handler寻找Handler的源码实现在各个HandlerMapping子类中的getHandlerInternal()中根据请求路径找到Handler的过程并不复杂因为路径和Handler的映射关系已经存在Map中了。
比较困难的点在于当DispatcherServlet接收到一个请求时该利用哪个HandlerMapping来寻找Handler呢
看源码
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;
}
很简单就是遍历找到就返回默认顺序为 什么是HandlerAdapter
找到了Handler之后接下来就该去执行了但是由于有不同种类的Handler所以执行方式是不一样的再来总结一下Handler的类型
实现了Controller接口的Bean对象执行的是Bean对象中的handleRequest()实现了HttpRequestHandler接口的Bean对象执行的是Bean对象中的handleRequest()添加了RequestMapping注解的方法具体为一个HandlerMethod执行的就是当前加了注解的方法一个HandlerFunction对象执行的是HandlerFunction对象中的handle()
所以按逻辑来说找到Handler之后我们得判断它的类型比如代码可能是这样的
Object handler mappedHandler.getHandler();
if (handler instanceof Controller) {((Controller)handler).handleRequest(request, response);
} else if (handler instanceof HttpRequestHandler) {((HttpRequestHandler)handler).handleRequest(request, response);
} else if (handler instanceof HandlerMethod) {((HandlerMethod)handler).getMethod().invoke(...);
} else if (handler instanceof HandlerFunction) {((HandlerFunction)handler).handle(...);
}
但是SpringMVC并不是这么写的还是采用的适配模式把不同种类的Handler适配成一个HandlerAdapter后续再执行HandlerAdapter的handle()方法就能执行不同种类Hanlder对应的方法。
针对不同的Handler会有不同的适配器
HttpRequestHandlerAdapterSimpleControllerHandlerAdapterRequestMappingHandlerAdapterHandlerFunctionAdapter
适配逻辑为
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遍历上面四个Adapter谁支持就返回谁比如判断的代码依次为
public boolean supports(Object handler) {return (handler instanceof HttpRequestHandler);
}public boolean supports(Object handler) {return (handler instanceof Controller);
}public final boolean supports(Object handler) {return (handler instanceof HandlerMethod supportsInternal((HandlerMethod) handler));
}public boolean supports(Object handler) {return handler instanceof HandlerFunction;
}
根据Handler适配出了对应的HandlerAdapter后就执行具体HandlerAdapter对象的handle()方法了比如
HttpRequestHandlerAdapter的handle()
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {((HttpRequestHandler) handler).handleRequest(request, response); SimpleControllerHandlerAdapter的handle()
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {return ((Controller) handler).handleRequest(request, response);
}
HandlerFunctionAdapter的handle()
HandlerFunction? handlerFunction (HandlerFunction?) handler;
serverResponse handlerFunction.handle(serverRequest);
因为这三个接收的直接就是Requeset对象不用SpringMVC做额外的解析所以比较简单比较复杂的是RequestMappingHandlerAdapter它执行的是加了RequestMapping的方法而这种方法的写法可以是多种多样SpringMVC需要根据方法的定义去解析Request对象从请求中获取出对应的数据然后传递给方法并执行。
RequestMapping方法参数解析
当SpringMVC接收到请求并找到了对应的Method之后就要执行该方法了不过在执行之前需要根据方法定义的参数信息从请求中获取出对应的数据然后将数据传给方法并执行。
一个HttpServletRequest通常有
request parameterrequest attributerequest sessionreqeust headerreqeust body
比如如下几个方法
public String test(String username) {return 123;
}
表示要从request parameter中获取key为username的value
public String test(RequestParam(uname) String username) {return 123;
}
表示要从request parameter中获取key为uname的value
public String test(RequestAttribute String username) {return 123;
}
表示要从request attribute中获取key为username的value
public String test(SessionAttribute String username) {return 123;
}
表示要从request session中获取key为username的value
public String test(RequestHeader String username) {return 123;
}
表示要从request header中获取key为username的value
public String test(RequestBody String username) {return 123;
}
表示获取整个请求体
所以我们发现SpringMVC要去解析方法参数看该参数到底是要获取请求中的哪些信息。
而这个过程源码中是通过HandlerMethodArgumentResolver来实现的比如
RequestParamMethodArgumentResolver负责处理RequestParamRequestHeaderMethodArgumentResolver负责处理RequestHeaderSessionAttributeMethodArgumentResolver负责处理SessionAttributeRequestAttributeMethodArgumentResolver负责处理RequestAttributeRequestResponseBodyMethodProcessor负责处理RequestBody还有很多其他的...
而在判断某个参数该由哪个HandlerMethodArgumentResolver处理时也是很粗暴
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;this.argumentResolverCache.put(parameter, result);break;}}}return result;}
就是遍历所有的HandlerMethodArgumentResolver哪个能支持处理当前这个参数就由哪个处理。
DispatcherServlet的init()方法
init()做了两件事情 完成了IOC的初始化 完成了SpringMVC核心组件的初始化
在这个方法里面主要会配置spring容器的父子容器并且还会执行initStrategies()初始化映射器和适配器分别对应initHandlerMappings()和initHandlerAdapters()这两个方法最后启动spring容器。
在这两个方法里都会先检查程序员自己有没有定义HandlerMapping.class或HandlerAdapter.class类型的bean如果没有的话就会走springmvc的默认策略getDefaultStrategies()去DispatcherServlet.properties文件中加载Bean默认HandlerMapping有3个BeanHandlerAdapter有4个Bean。 DispatcherServlet的doService()方法
tomcat会处理请求然后调用service()方法service方法调用DispatcherServlet的doService()方法doService()调用doDispatch()也就是一套模板方法。
service方法是在用户请求到来的时候触发的。也就是具体处理请求的方法。我们来看下直接进入到doDispatch方法中
核心流程如下
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {// 检查是否是multipart请求processedRequest checkMultipart(request);// 进行映射 找到对应的handlermappedHandler getHandler(processedRequest);if (mappedHandler null) {//404noHandlerFound(processedRequest, response);return;}// 找到最合适的HandlerAdapterHandlerAdapter ha getHandlerAdapter(mappedHandler.getHandler());// 前置拦截器if (!mappedHandler.applyPreHandle(processedRequest, response)) {// 返回false就不进行后续处理了return;}// 真正执行handlemv ha.handle(processedRequest, response, mappedHandler.getHandler());//后置拦截器mappedHandler.applyPostHandle(processedRequest, response, mv);// 渲染视图processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
SpringBoot整合SpringMVC
然后我们来看下载SpringBoot项目中是怎么自动装配SpringMVC框架的首先我们找到对应的配置类 同时我们也需要关注下这个配置类 在这个配置类中注入的HandlerMapping和HandlerAdapter的具体实现类 同时也注入了DispatcherServlet SpringMVC执行流程图
spring MVC