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)方法的具體實現(xiàn)見下源代碼。根據(jù)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類中實現(xiàn)了HandlerAdapter接口中的三個抽象方法。
public class SimpleControllerHandlerAdapter implements HandlerAdapter {
@Override
public boolean supports(Object handler) {
// 判斷找到的handler是否為Controller類型。HelloController類實現(xiàn)了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報頭發(fā)送給HTTP客戶端,并與客戶端返回的If-Modified-Since報頭進行比較。只有在進行了修改后,內容才會重新生成。
* 參數(shù):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執(zhí)行Handler對象,最終得到ModelAndView對象。
@Override
@Nullable
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
// handler處理器執(zhí)行handleRequest方法,主要作用是找到HelloController類中重寫的handleRequest重寫的業(yè)務邏輯方法
return ((Controller) handler).handleRequest(request, response);
}
4.2 HandlerAdapter的執(zhí)行
DispatcherServlet會根據(jù)handlerMapping傳過來的controller與已經(jīng)注冊好了的HandlerAdapter相匹配,看哪一種HandlerAdapter是支持該controller類型的,如果找到了其中一種HandlerAdapter是支持傳過來的controller類型,那么該HandlerAdapter會調用自己的handle方法,handle方法運用Java反射機制執(zhí)行controller的具體方法來獲得ModelAndView。
5 視圖解析器ViewResolver
SpringMVC用于處理視圖最重要的兩個接口是ViewResolver和View。ViewResolver的主要作用是把一個邏輯上的視圖名稱解析為一個真正的視圖,SpringMVC中用于把View對象呈現(xiàn)給客戶端的是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類,根據(jù)返回頁面的名稱拼接前綴和后綴,最終形成一個完整頁面的路徑。例如:/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:"; // 轉發(fā)
@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執(zhí)行流程分析
1.SpringMVC執(zhí)行流程圖
2.SpringMVC執(zhí)行步驟
1.客戶端瀏覽器發(fā)送請求給服務器中的前端控制器DispatcherServlet;
2.用戶根據(jù)請求中的url路徑,通過HandlerMapping處理器映射器,找到匹配的Controller;
3.HandlerMapping返回一個處理器執(zhí)行鏈,包括N個攔截器與1個Controller的處理器。并把處理器執(zhí)行鏈,返回給前端控制器DispatcherServlet;
4.前端控制器DispatcherServlet得到處理器執(zhí)行鏈之后,把Controller的Handler發(fā)送給HandlerAdapter處理器適配器;
5.HandlerAdapter根據(jù)supports(Object handler)方法,也就是內部的匹配規(guī)則,判斷該處理器Handler是否實現(xiàn)了Controller接口;
6.Handler處理器找到具體的方法handler.handleRequest(request, response),根據(jù)請求執(zhí)行Controller類中的方法;
7.Controller類執(zhí)行完畢,然后返回一個ModelAndView對象給Handler處理器;
8.Handler處理器把ModelAndView對象返回給HandlerAdapter;
9.HandlerAdapter把ModelAndView對象返回給前端控制器DispathcerServlet;
10.DispathcerServlet把ModelAndView對象傳遞給ViewResolver視圖解析器,根據(jù)jsp頁面的名稱拼接路;
11.ViewResolver視圖解析器返回給DispathcerServlet前端控制器;
12.DispathcerServlet拿到jsp路徑,由web容器對jsp頁面進行視圖渲染;
13.Web容器把響應結果返回給瀏覽器。
3.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 北京千鋒互聯(lián)科技有限公司 .All Right 京ICP備12003911號-5 京公網(wǎng)安備 11010802035720號