写在前面:
我是「沸羊羊_」,昵称来自于姓名的缩写 fyy ,之前呕心沥血经营的博客因手残意外注销,现经营此账号。
本人是个小菜,正向着全栈工程师的方向努力着,文章可能并不高产,也很基础,但每写一篇都在用心总结,请大佬勿喷。
如果您对编程有兴趣,请关注我的动态,一起学习研究。
感谢每位读者!
文章目录
- 认识SpringMVC
- SpringMVC 处理请求过程
- Servlet 与 SpringMVC
- Structs2 与 Spring MVC
- SpringMVC源码分析
认识SpringMVC
SpringMVC 框架是以请求为驱动,围绕 Servlet 设计,将请求发给控制器,然后通过模型对象,分派器来展示请求结果视图。其中核心类是 DispatcherServlet,它是一个 Servlet,顶层是实现的Servlet接口。
SpringMVC 处理请求过程
- 客户端发起请求,会首先经过前端控制器 DispatcherServlet 进行转发,转发到 Handler Mapping
- DispatcherServlet 从 Handler Mapping 查找处理请求的 Controller,Handler Mapping 作用就是完成 URL 到 Controller 的映射
- Controller 处理请求并返回 ModelAndView 对象,ModelAndView 是封装结果视图的组件
- 再将视图结果返回给客户端
Servlet 与 SpringMVC
SpringMVC 是在 Servlet 的基础上进行了扩展,看看他们的继承关系是什么样的。
Servlet 继承关系
SpringMVC 继承关系
Servlet 与 SpringMVC 对比
- Servlet 需要每个请求都在 web.xml 文件中配置一个 sevlet 节点
- SpringMVC 的 DispatcherServlet 会拦截所有请求,让 Controller 去处理
Structs2 与 Spring MVC
相同点
- 都是基于MVC模型的
不同点
- Structs2 是基于类的,一个 request 创建一个 action,一个action 对应一个 request ;Servlet 是基于方法的,也就是一个 request 对应一个方法
- Structs2 入口是 Filter;SpringMVC 入口是 Servlet
- SpringMVC 的开发速度和性能优于 Structs2 ,流程更易理解
- SpringMVC 和 Spring 是无缝的,可以认为 SpringMVC 是100% 零配置
SpringMVC源码分析
1、ApplicationContext 初始化时建立所有的URL和Controller 的对应关系
protected void detectHandlers() throws BeansException {
//日志级别是否是 Debug
if (logger.isDebugEnabled()) {
//应用上下文就是工程的访问路径
logger.debug("Looking for URL mappings in application context: " + getApplicationContext());
}
// 获取ApplicationContext容器中所有bean的Name---Controller
String[] beanNames = (this.detectHandlersInAncestorContexts ?
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
getApplicationContext().getBeanNamesForType(Object.class));
// 遍历beanNames,并找到这些bean对应的url
for (String beanName : beanNames) {
// 获取Controller上的所有url(类上的url+方法上的url)
String[] urls = determineUrlsForHandler(beanName);
if (!ObjectUtils.isEmpty(urls)) {
// 保存urls和beanName的对应关系,put it to Map<urls,beanName>,该方法在父类AbstractUrlHandlerMapping中实现
registerHandler(urls, beanName);
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Rejected bean name '" + beanName + "': no URL paths identified");
}
}
}
}
2、根据访问URL找到对应 Controller 中处理请求的方法
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
int interceptorIndex = -1;
try {
ModelAndView mv;
boolean errorView = false;
try {
// 1.检查是否是文件上传的请求
processedRequest = checkMultipart(request);
// 2.取得处理当前请求的controller,这里也称为hanlder,处理器,第一个步骤的意义就在这里体现了.
这里并不是直接返回controller,而是返回的HandlerExecutionChain请求处理器链对象,该对象封装了handler和interceptors.
mappedHandler = getHandler(processedRequest, false);
// 如果handler为空,则返回404
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
//3. 获取处理request的处理器适配器handler adapter
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 处理 last-modified 请求头
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (logger.isDebugEnabled()) {
String requestUri = urlPathHelper.getRequestUri(request);
logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
// 4.拦截器的预处理方法
HandlerInterceptor[] interceptors = mappedHandler.getInterceptors();
if (interceptors != null) {
for (int i = 0; i < interceptors.length; i++) {
HandlerInterceptor interceptor = interceptors[i];
if (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler())) {
triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);
return;
}
interceptorIndex = i;
}
}
// 5.实际的处理器处理请求,返回结果视图对象
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
// 结果视图对象的处理
if (mv != null && !mv.hasView()) {
mv.setViewName(getDefaultViewName(request));
}
// 6.拦截器的后处理方法
if (interceptors != null) {
for (int i = interceptors.length - 1; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
interceptor.postHandle(processedRequest, response, mappedHandler.getHandler(), mv);
}
}
}
catch (ModelAndViewDefiningException ex) {
logger.debug("ModelAndViewDefiningException encountered", ex);
mv = ex.getModelAndView();
}
catch (Exception ex) {
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
mv = processHandlerException(processedRequest, response, handler, ex);
errorView = (mv != null);
}
if (mv != null && !mv.wasCleared()) {
render(mv, processedRequest, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
"': assuming HandlerAdapter completed request handling");
}
}
// 请求成功响应之后的方法
triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);
}
3、反射调用处理请求的方法返回结果视图
protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
// 1.获取方法解析器
ServletHandlerMethodResolver methodResolver = getMethodResolver(handler);
// 2.解析request中的url,获取处理request的方法
//通过 request 找 controller 中的处理方法,request的url与 controller 的url 进行匹配
Method handlerMethod = methodResolver.resolveHandlerMethod(request);
// 3.方法调用器
ServletHandlerMethodInvoker methodInvoker = new ServletHandlerMethodInvoker(methodResolver);
ServletWebRequest webRequest = new ServletWebRequest(request, response);
ExtendedModelMap implicitModel = new BindingAwareModelMap();
// 4.执行方法
Object result = methodInvoker.invokeHandlerMethod(handlerMethod, handler, webRequest, implicitModel);
// 5.封装结果视图
ModelAndView mav =
methodInvoker.getModelAndView(handlerMethod, handler.getClass(), result, implicitModel, webRequest);
methodInvoker.updateModelAttributes(handler, (mav != null ? mav.getModel() : null), implicitModel, webRequest);
return mav;
}