当前位置: 首页 / 技术干货 / 正文
SpringMVC源码解析(四)

2023-03-09

视图 handleradapter 处理器 对象 返回

  4 处理器适配器HandlerAdapter

  4.1 HandlerAdapter源码分析

  1.在DispatcherServlet类中的doDispatch(request, response)方法中调用getHandlerAdapter(mappedHandler.getHandler())获取处理器适配器。

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
// ...
try {
// ...
try {
// ...

// 确定当前请求的处理程序适配器。
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
}
// ...
}
// ...
}

  2.getHandlerAdapter(Object handler)方法的具体实现见下源代码。根据Handler找到支持它的HandlerAdapter对象。

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");
}

  3.在SimpleControllerHandlerAdapter类中实现了HandlerAdapter接口中的三个抽象方法。

public class SimpleControllerHandlerAdapter implements HandlerAdapter {

@Override
public boolean supports(Object handler) {
// 判断找到的handler是否为Controller类型。HelloController类实现了Controller接口,所以处理器能够找到该类
return (handler instanceof Controller);
}

@Override
@Nullable
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
// 通过handler处理器,调用控制器的handlerRequest方法,来处理相应的请求
return ((Controller) handler).handleRequest(request, response);
}

/**
* 与HttpServlet的getLastModified方法的约定相同。在请求处理之前调用。

* 返回值将作为Last-Modified报头发送给HTTP客户端,并与客户端返回的If-Modified-Since报头进行比较。只有在进行了修改后,内容才会重新生成。

* 参数:request - 当前HTTP请求

* 返回:上次修改基础资源的时间,或-1表示必须始终重新生成内容
*/
@Override
@SuppressWarnings("deprecation")
public long getLastModified(HttpServletRequest request, Object handler) {
if (handler instanceof LastModified) {
return ((LastModified) handler).getLastModified(request);
}
return -1L;
}

}

  4.从SimpleControllerHandlerAdapter类中handle方法可以看出,通过HandlerAdapter执行Handler对象,最终得到ModelAndView对象。

@Override
@Nullable
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
// handler处理器执行handleRequest方法,主要作用是找到HelloController类中重写的handleRequest重写的业务逻辑方法
return ((Controller) handler).handleRequest(request, response);
}

  4.2 HandlerAdapter的执行

  DispatcherServlet会根据handlerMapping传过来的controller与已经注册好了的HandlerAdapter相匹配,看哪一种HandlerAdapter是支持该controller类型的,如果找到了其中一种HandlerAdapter是支持传过来的controller类型,那么该HandlerAdapter会调用自己的handle方法,handle方法运用Java反射机制执行controller的具体方法来获得ModelAndView。

  5 视图解析器ViewResolver

  SpringMVC用于处理视图最重要的两个接口是ViewResolver和View。ViewResolver的主要作用是把一个逻辑上的视图名称解析为一个真正的视图,SpringMVC中用于把View对象呈现给客户端的是View对象本身,而ViewResolver只是把逻辑视图名称解析为对象的View对象。View接口的主要作用是用于处理视图,然后返回给客户端。

  5.1 ViewResolver源码分析

  1.内部资源视图解析器InternalResourceViewResolver类,进行页面渲染时,需要使用jstl标准标签库。

public class InternalResourceViewResolver extends UrlBasedViewResolver {
// 在进行页面渲染时,需要使用jstl的标准标签库
private static final boolean jstlPresent = ClassUtils.isPresent(
"javax.servlet.jsp.jstl.core.Config", InternalResourceViewResolver.class.getClassLoader());

// ...
}

  2.InternalResourceViewResolver类的父类UrlBasedViewResolver类,根据返回页面的名称拼接前缀和后缀,最终形成一个完整页面的路径。例如:/WEB-INF/hello.jsp。

public class UrlBasedViewResolver extends AbstractCachingViewResolver implements Ordered {

public static final String REDIRECT_URL_PREFIX = "redirect:"; // 重定向

public static final String FORWARD_URL_PREFIX = "forward:"; // 转发

@Nullable
private Class<?> viewClass;

private String prefix = ""; // 前缀

private String suffix = ""; // 后缀

// ...

protected AbstractUrlBasedView buildView(String viewName) throws Exception {
AbstractUrlBasedView view = instantiateView();
view.setUrl(getPrefix() + viewName + getSuffix());
view.setAttributesMap(getAttributesMap());

String contentType = getContentType();
if (contentType != null) {
view.setContentType(contentType);
}

String requestContextAttribute = getRequestContextAttribute();
if (requestContextAttribute != null) {
view.setRequestContextAttribute(requestContextAttribute);
}

Boolean exposePathVariables = getExposePathVariables();
if (exposePathVariables != null) {
view.setExposePathVariables(exposePathVariables);
}
Boolean exposeContextBeansAsAttributes = getExposeContextBeansAsAttributes();
if (exposeContextBeansAsAttributes != null) {
view.setExposeContextBeansAsAttributes(exposeContextBeansAsAttributes);
}
String[] exposedContextBeanNames = getExposedContextBeanNames();
if (exposedContextBeanNames != null) {
view.setExposedContextBeanNames(exposedContextBeanNames);
}

return view;
}

protected View applyLifecycleMethods(String viewName, AbstractUrlBasedView view) {
ApplicationContext context = getApplicationContext();
if (context != null) {
Object initialized = context.getAutowireCapableBeanFactory().initializeBean(view, viewName);
if (initialized instanceof View) {
return (View) initialized;
}
}
return view;
}
}

  5.2 ViewResolver解析流程

  1.将SpringMVC控制器中的返回结果封装成一个ModelAndView对象。

  2.通过SpringMVC中的视图解析器,使用ViewResolver对控制器返回的ModelAndView对象进行解析,将逻辑视图转换成物理视图。

  3.调用View接口中的render()方法对物理视图进行渲染。

  6 SpringMVC执行流程分析

  1.SpringMVC执行流程图

  2.SpringMVC执行步骤

  1.客户端浏览器发送请求给服务器中的前端控制器DispatcherServlet;

  2.用户根据请求中的url路径,通过HandlerMapping处理器映射器,找到匹配的Controller;

  3.HandlerMapping返回一个处理器执行链,包括N个拦截器与1个Controller的处理器。并把处理器执行链,返回给前端控制器DispatcherServlet;

  4.前端控制器DispatcherServlet得到处理器执行链之后,把Controller的Handler发送给HandlerAdapter处理器适配器;

  5.HandlerAdapter根据supports(Object handler)方法,也就是内部的匹配规则,判断该处理器Handler是否实现了Controller接口;

  6.Handler处理器找到具体的方法handler.handleRequest(request, response),根据请求执行Controller类中的方法;

  7.Controller类执行完毕,然后返回一个ModelAndView对象给Handler处理器;

  8.Handler处理器把ModelAndView对象返回给HandlerAdapter;

  9.HandlerAdapter把ModelAndView对象返回给前端控制器DispathcerServlet;

  10.DispathcerServlet把ModelAndView对象传递给ViewResolver视图解析器,根据jsp页面的名称拼接路;

  11.ViewResolver视图解析器返回给DispathcerServlet前端控制器;

  12.DispathcerServlet拿到jsp路径,由web容器对jsp页面进行视图渲染;

  13.Web容器把响应结果返回给浏览器。

  3.SpringMVC核心组件

QQ截图20230309160031

好程序员公众号

  • · 剖析行业发展趋势
  • · 汇聚企业项目源码

好程序员开班动态

More+
  • HTML5大前端 <高端班>

    开班时间:2021-04-12(深圳)

    开班盛况

    开班时间:2021-05-17(北京)

    开班盛况
  • 大数据+人工智能 <高端班>

    开班时间:2021-03-22(杭州)

    开班盛况

    开班时间:2021-04-26(北京)

    开班盛况
  • JavaEE分布式开发 <高端班>

    开班时间:2021-05-10(北京)

    开班盛况

    开班时间:2021-02-22(北京)

    开班盛况
  • Python人工智能+数据分析 <高端班>

    开班时间:2021-07-12(北京)

    预约报名

    开班时间:2020-09-21(上海)

    开班盛况
  • 云计算开发 <高端班>

    开班时间:2021-07-12(北京)

    预约报名

    开班时间:2019-07-22(北京)

    开班盛况
IT培训IT培训
在线咨询
IT培训IT培训
试听
IT培训IT培训
入学教程
IT培训IT培训
立即报名
IT培训

Copyright 2011-2023 北京千锋互联科技有限公司 .All Right 京ICP备12003911号-5 京公网安备 11010802035720号