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核心组件
上一篇:SpringMVC源码解析(三)
开班时间:2021-04-12(深圳)
开班盛况开班时间:2021-05-17(北京)
开班盛况开班时间:2021-03-22(杭州)
开班盛况开班时间:2021-04-26(北京)
开班盛况开班时间:2021-05-10(北京)
开班盛况开班时间:2021-02-22(北京)
开班盛况开班时间:2021-07-12(北京)
预约报名开班时间:2020-09-21(上海)
开班盛况开班时间:2021-07-12(北京)
预约报名开班时间:2019-07-22(北京)
开班盛况Copyright 2011-2023 北京千锋互联科技有限公司 .All Right 京ICP备12003911号-5 京公网安备 11010802035720号