該系列檔案是本人在學習 Spring MVC 的原始碼程序中總結下來的,可能對讀者不太友好,請結合我的原始碼注釋 Spring MVC 原始碼分析 GitHub 地址 進行閱讀
Spring 版本:5.2.4.RELEASE
該系列其他檔案請查看:《精盡 Spring MVC 原始碼分析 - 文章導讀》
HandlerAdapter 組件
HandlerAdapter 組件,處理器的配接器,因為處理器 handler 的型別是 Object 型別,需要有一個呼叫者來實作 handler 是怎么被執行,Spring 中的處理器的實作多變,比如用戶的處理器可以實作 Controller 介面或者 HttpRequestHandler 介面,也可以用 @RequestMapping 注解將方法作為一個處理器等,這就導致 Spring MVC 無法直接執行這個處理器,所以這里需要一個處理器配接器,由它去執行處理器
由于 HandlerMapping 組件涉及到的內容較多,考慮到內容的排版,所以將這部分內容拆分成了五個模塊,依次進行分析:
- 《HandlerAdapter 組件(一)之 HandlerAdapter》
- 《HandlerAdapter 組件(二)之 ServletInvocableHandlerMethod》
- 《HandlerAdapter 組件(三)之 HandlerMethodArgumentResolver》
- 《HandlerAdapter 組件(四)之 HandlerMethodReturnValueHandler》
- 《HandlerAdapter 組件(五)之 HttpMessageConverter》
HandlerAdapter 組件(一)之 HandlerAdapter
先來回顧一下在 DispatcherServlet 中處理請求的程序中哪里使用到 HandlerMapping 組件,可以回到《一個請求的旅行程序》中的 DispatcherServlet 的 doDispatch 方法中看看,如下:
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
ModelAndView mv = null;
// ... 省略相關代碼
// <3> 獲得請求對應的 HandlerExecutionChain 物件(HandlerMethod 和 HandlerInterceptor 攔截器們)
mappedHandler = getHandler(processedRequest);
// ... 省略相關代碼
// <4> 獲得當前 handler 對應的 HandlerAdapter 物件
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// ... 省略相關代碼
// <6> 真正的呼叫 handler 方法,也就是執行對應的方法,并回傳視圖
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
// ... 省略相關代碼
}
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 [...");
}
通過遍歷 HandlerAdapter 組件們,判斷是否支持處理該 handler 處理器,支持則回傳該 HandlerAdapter 組件,注意,這里是通過一個一個的 HandlerAdapter 組件去判斷是否支持該處理器,如果支持則直接回傳這個 HandlerAdapter 組件,不會繼續下去,所以獲取處理器對應 HandlerAdapter 組件是有一定的先后順序的,默認是HttpRequestHandlerAdapter -> SimpleControllerHandlerAdapter -> RequestMappingHandlerAdapter
本文涉及到的內容適中,可以先查看我的總結
HandlerAdapter 介面
org.springframework.web.servlet.HandlerAdapter介面,處理器的配接器,去執行處理器,代碼如下:
public interface HandlerAdapter {
/**
* 是否支持該處理器
*/
boolean supports(Object handler);
/**
* 執行處理器,回傳 ModelAndView 結果
*/
@Nullable
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
/**
* 回傳請求的最新更新時間,如果不支持該操作,則回傳 -1 即可
*/
long getLastModified(HttpServletRequest request, Object handler);
}
HandlerAdapter 介面的體系結構如下:
沒有特別多?? 心里有點點欣慰,其中 RequestMappingHandlerAdapter 就是基于@RequestMapping 等注解的 HandlerMethod 的 HandlerMethodAdapter 實作類,名字都差不多
初始化程序
在 DispatcherServlet 的 initHandlerAdapters(ApplicationContext context) 方法,會在 onRefresh 方法被呼叫,初始化 HandlerAdapter 組件,方法如下:
private void initHandlerAdapters(ApplicationContext context) {
this.handlerAdapters = null;
if (this.detectAllHandlerAdapters) {
// Find all HandlerAdapters in the ApplicationContext, including ancestor contexts.
Map<String, HandlerAdapter> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerAdapters = new ArrayList<>(matchingBeans.values());
// We keep HandlerAdapters in sorted order.
AnnotationAwareOrderComparator.sort(this.handlerAdapters);
}
}
else {
try {
HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);
this.handlerAdapters = Collections.singletonList(ha);
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore, we'll add a default HandlerAdapter later.
}
}
// Ensure we have at least some HandlerAdapters, by registering
// default HandlerAdapters if no other adapters are found.
/**
* 如果未獲得到,則獲得默認配置的 HandlerAdapter 類
* {@link org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter}
* {@link org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter}
* {@link org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter}
*/
if (this.handlerAdapters == null) {
this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);
if (logger.isTraceEnabled()) {
logger.trace("No HandlerAdapters declared for servlet '" + getServletName() +
"': using default strategies from DispatcherServlet.properties");
}
}
}
-
如果“開啟”探測功能,則掃描已注冊的 HandlerAdapter 的 Bean 們,添加到
handlerAdapters中,默認開啟,這里會進行排序,可以通過實作 Order 介面設定排序值 -
如果“關閉”探測功能,則獲得 Bean 名稱為 "handlerAdapter" 對應的 Bean ,將其添加至
handlerAdapters -
如果未獲得到,則獲得默認配置的 HandlerAdapter 類,呼叫
getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface)方法,就是從DispatcherServlet.properties檔案中讀取 HandlerAdapter 的默認實作類,如下:org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\ org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\ org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter可以看到對應的是 HttpRequestHandlerAdapter、SimpleControllerHandlerAdapter、RequestMappingHandlerAdapter 三個實作類,接下來就一個一個分析
HttpRequestHandlerAdapter
org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,實作 HandlerAdapter 介面,基于 HttpRequestHandler 介面的 HandlerAdapter 實作類,代碼如下:
public class HttpRequestHandlerAdapter implements HandlerAdapter {
@Override
public boolean supports(Object handler) {
// 判斷是 HttpRequestHandler 型別
return (handler instanceof HttpRequestHandler);
}
@Override
@Nullable
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
// HttpRequestHandler 型別的呼叫
((HttpRequestHandler) handler).handleRequest(request, response);
return null;
}
@Override
public long getLastModified(HttpServletRequest request, Object handler) {
// 處理器實作了 LastModified 介面的情況下
if (handler instanceof LastModified) {
return ((LastModified) handler).getLastModified(request);
}
return -1L;
}
}
// org.springframework.web.HttpRequestHandler.java
@FunctionalInterface
public interface HttpRequestHandler {
/**
* 處理請求
*/
void handleRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException;
}
邏輯比較簡單,如果這個處理器實作了 HttpRequestHandler 介面,則使用 HttpRequestHandlerAdapter 呼叫該處理器的 handleRequest(HttpServletRequest request, HttpServletResponse response) 方法去處理器請求,回傳 null
這種處理器如何配置呢?
可以回到《HandlerMapping 組件(四)之 AbstractUrlHandlerMapping》的 SimpleUrlHandlerMapping 或者 BeanNameUrlHandlerMapping 小節中的使用示例看看
SimpleControllerHandlerAdapter
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,實作 HandlerAdapter 介面,基于 Controller 介面的 HandlerAdapter 實作類,代碼如下:
public class SimpleControllerHandlerAdapter implements HandlerAdapter {
@Override
public boolean supports(Object handler) {
// <1> 判斷是 Controller 型別
return (handler instanceof Controller);
}
@Override
@Nullable
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
// <2> Controller 型別的呼叫
return ((Controller) handler).handleRequest(request, response);
}
@Override
public long getLastModified(HttpServletRequest request, Object handler) {
// 處理器實作了 LastModified 介面的情況下
if (handler instanceof LastModified) {
return ((LastModified) handler).getLastModified(request);
}
return -1L;
}
}
@FunctionalInterface
public interface Controller {
/**
* 處理請求
*/
@Nullable
ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception;
}
邏輯比較簡單,和 HttpRequestHandlerAdapter 差不多,如果這個處理器實作了 Controoler 介面,則使用 HttpRequestHandlerAdapter 呼叫該處理器的 handleRequest(HttpServletRequest request, HttpServletResponse response) 方法去處理器請求,直接回傳處理器執行后回傳 ModelAndView
這種處理器如何配置和 HttpRequestHandlerAdapter 相同,見上文描述
SimpleServletHandlerAdapter 實作類就不講述了,因為默認的 HandlerAdapter 實作類中沒有它
邏輯實作和 SimpleControllerHandlerAdapter 差不多,區別在于它判斷是否為
javax.servlet.Servlet物件,是的話則呼叫其service方法,回傳該方法執行后回傳的ModelAndView物件
AbstractHandlerMethodAdapter
org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter,實作 HandlerAdapter、Ordered 介面,繼承 WebContentGenerator 抽象類,基于 HandlerMethod 的 HandlerMethodAdapter 抽象類
構造方法
public abstract class AbstractHandlerMethodAdapter extends WebContentGenerator implements HandlerAdapter, Ordered {
/** 最低優先級 */
private int order = Ordered.LOWEST_PRECEDENCE;
public AbstractHandlerMethodAdapter() {
// no restriction of HTTP methods by default
// 呼叫 WebContentGenerator 類的構造方法
// 引數 restrictDefaultSupportedMethods 引數為 false ,表示不需要嚴格校驗 HttpMethod
super(false);
}
}
supports方法
實作 supports(Object handler) 方法,判斷是否支持該處理器,代碼如下:
@Override
public final boolean supports(Object handler) {
return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}
protected abstract boolean supportsInternal(HandlerMethod handlerMethod);
- 處理器必須是 HandlerMethod 型別,也就是在《HandlerMapping 組件(三)之 AbstractHandlerMethodMapping》講到的通過
@RequestMapping等注解方法所生成對應 HandlerMethod 物件 - 還需要呼叫抽象方法
supportsInternal(HandlerMethod handlerMethod)判斷是否支持, 交由子類去實作,詳情見下文
handle方法
實作 handle(HttpServletRequest request, HttpServletResponse response, Object handler) 方法,用于處理請求,執行該處理器,代碼如下:
@Override
@Nullable
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return handleInternal(request, response, (HandlerMethod) handler);
}
@Nullable
protected abstract ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception;
- 如果該 HandlerAdapter 支持這個處理器,那么則會呼叫該方法去處理請求,執行這個處理器
- 直接呼叫
handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod)抽象方法,交由子類去實作,詳情見下文
getLastModified方法
實作 getLastModified(HttpServletRequest request, Object handler) 方法,獲得最后更新時間,代碼如下
@Override
public final long getLastModified(HttpServletRequest request, Object handler) {
return getLastModifiedInternal(request, (HandlerMethod) handler);
}
protected abstract long getLastModifiedInternal(HttpServletRequest request, HandlerMethod handlerMethod);
- 直接呼叫
getLastModifiedInternal(HttpServletRequest request, HandlerMethod handlerMethod)抽象方法,交由子類去實作,詳情見下文
RequestMappingHandlerAdapter
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter,實作 BeanFactoryAware、InitializingBean 介面,繼承 AbstractHandlerMethodAdapter 抽象類,基于 @RequestMapping 注解的 HandlerMethod 處理器的 HandlerMethodAdapter 實作類
構造方法
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
implements BeanFactoryAware, InitializingBean {
/**
* MethodFilter that matches {@link InitBinder @InitBinder} methods.
*/
public static final MethodFilter INIT_BINDER_METHODS = method ->
AnnotatedElementUtils.hasAnnotation(method, InitBinder.class);
/**
* MethodFilter that matches {@link ModelAttribute @ModelAttribute} methods.
*/
public static final MethodFilter MODEL_ATTRIBUTE_METHODS = method ->
(!AnnotatedElementUtils.hasAnnotation(method, RequestMapping.class) &&
AnnotatedElementUtils.hasAnnotation(method, ModelAttribute.class));
@Nullable
private List<HandlerMethodArgumentResolver> customArgumentResolvers;
@Nullable
private HandlerMethodArgumentResolverComposite argumentResolvers;
@Nullable
private HandlerMethodArgumentResolverComposite initBinderArgumentResolvers;
@Nullable
private List<HandlerMethodReturnValueHandler> customReturnValueHandlers;
@Nullable
private HandlerMethodReturnValueHandlerComposite returnValueHandlers;
@Nullable
private List<ModelAndViewResolver> modelAndViewResolvers;
private ContentNegotiationManager contentNegotiationManager = new ContentNegotiationManager();
private List<HttpMessageConverter<?>> messageConverters;
private List<Object> requestResponseBodyAdvice = new ArrayList<>();
@Nullable
private WebBindingInitializer webBindingInitializer;
private AsyncTaskExecutor taskExecutor = new SimpleAsyncTaskExecutor("MvcAsync");
@Nullable
private Long asyncRequestTimeout;
private CallableProcessingInterceptor[] callableInterceptors = new CallableProcessingInterceptor[0];
private DeferredResultProcessingInterceptor[] deferredResultInterceptors = new DeferredResultProcessingInterceptor[0];
private ReactiveAdapterRegistry reactiveAdapterRegistry = ReactiveAdapterRegistry.getSharedInstance();
private boolean ignoreDefaultModelOnRedirect = false;
private int cacheSecondsForSessionAttributeHandlers = 0;
/**
* 是否對相同 Session 加鎖
*/
private boolean synchronizeOnSession = false;
private SessionAttributeStore sessionAttributeStore = new DefaultSessionAttributeStore();
private ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();
@Nullable
private ConfigurableBeanFactory beanFactory;
// ========== 快取 ==========
private final Map<Class<?>, SessionAttributesHandler> sessionAttributesHandlerCache = new ConcurrentHashMap<>(64);
private final Map<Class<?>, Set<Method>> initBinderCache = new ConcurrentHashMap<>(64);
private final Map<ControllerAdviceBean, Set<Method>> initBinderAdviceCache = new LinkedHashMap<>();
private final Map<Class<?>, Set<Method>> modelAttributeCache = new ConcurrentHashMap<>(64);
private final Map<ControllerAdviceBean, Set<Method>> modelAttributeAdviceCache = new LinkedHashMap<>();
// ... 省略 getter、setter 方法
public RequestMappingHandlerAdapter() {
// 初始化 messageConverters
StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter();
stringHttpMessageConverter.setWriteAcceptCharset(false); // see SPR-7316
this.messageConverters = new ArrayList<>(4);
this.messageConverters.add(new ByteArrayHttpMessageConverter());
this.messageConverters.add(stringHttpMessageConverter);
try {
this.messageConverters.add(new SourceHttpMessageConverter<>());
}
catch (Error err) {
// Ignore when no TransformerFactory implementation is available
}
this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());
}
}
有許多的屬性,不著急理解,先列幾個主要的屬性物件:
HandlerMethodArgumentResolverComposite argumentResolvers:引數處理器組合物件HandlerMethodReturnValueHandlerComposite returnValueHandlers:回傳值處理器組合物件List<HttpMessageConverter<?>> messageConverters:HTTP 訊息轉換器集合物件List<Object> requestResponseBodyAdvice: RequestResponseAdvice 集合物件
在構造方法中默認會添加了四個 HttpMessageConverter 物件,當然,默認還會添加其他的,例如 MappingJackson2HttpMessageConverter 為 JSON 訊息格式的轉換器
1.afterPropertiesSet 初始化方法
因為 RequestMappingHandlerAdapter 實作了 InitializingBean 介面,在 Sping 初始化該 Bean 的時候,會呼叫該方法,完成一些初始化作業,方法如下:
@Override
public void afterPropertiesSet() {
// Do this first, it may add ResponseBody advice beans
// <1> 初始化 ControllerAdvice 相關
initControllerAdviceCache();
// <2> 初始化 argumentResolvers 屬性
if (this.argumentResolvers == null) {
List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
// <3> 初始化 initBinderArgumentResolvers 屬性
if (this.initBinderArgumentResolvers == null) {
List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
// <4> 初始化 returnValueHandlers 屬性
if (this.returnValueHandlers == null) {
List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
}
}
-
呼叫
initControllerAdviceCache()方法,初始化 ControllerAdvice 相關,詳情見下文 -
初始化
argumentResolvers屬性,呼叫getDefaultArgumentResolvers()方法,獲得默認的 HandlerMethodArgumentResolver 陣列,詳情見下文 -
初始化
initBinderArgumentResolvers屬性,呼叫getDefaultInitBinderArgumentResolvers()方法,獲得默認的 HandlerMethodArgumentResolver 陣列,詳情見下文 -
初始化
returnValueHandlers屬性,呼叫getDefaultReturnValueHandlers()方法,獲得默認的 HandlerMethodReturnValueHandler 陣列,詳情見下文
1.1 initControllerAdviceCache
initControllerAdviceCache() 方法,初始化 ControllerAdvice 相關,方法如下:
private void initControllerAdviceCache() {
if (getApplicationContext() == null) {
return;
}
// <1> 掃描 @ControllerAdvice 注解的 Bean 們,生成對應的 ControllerAdviceBean 物件,并將進行排序
List<ControllerAdviceBean> adviceBeans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());
AnnotationAwareOrderComparator.sort(adviceBeans);
List<Object> requestResponseBodyAdviceBeans = new ArrayList<>();
// <2> 遍歷 ControllerAdviceBean 陣列
for (ControllerAdviceBean adviceBean : adviceBeans) {
Class<?> beanType = adviceBean.getBeanType();
if (beanType == null) {
throw new IllegalStateException("Unresolvable type for ControllerAdviceBean: " + adviceBean);
}
// <2.1> 掃描有 `@ModelAttribute` ,無 `@RequestMapping` 注解的方法,添加到 `modelAttributeAdviceCache` 屬性中
// 該類方法用于在執行方法前修改 Model 物件
Set<Method> attrMethods = MethodIntrospector.selectMethods(beanType, MODEL_ATTRIBUTE_METHODS);
if (!attrMethods.isEmpty()) {
this.modelAttributeAdviceCache.put(adviceBean, attrMethods);
}
// <2.2> 掃描有 `@InitBinder` 注解的方法,添加到 `initBinderAdviceCache` 屬性中
// 該類方法用于在執行方法前初始化資料系結器
Set<Method> binderMethods = MethodIntrospector.selectMethods(beanType, INIT_BINDER_METHODS);
if (!binderMethods.isEmpty()) {
this.initBinderAdviceCache.put(adviceBean, binderMethods);
}
// <2.3> 如果是 RequestBodyAdvice 或 ResponseBodyAdvice 的子類,添加到 requestResponseBodyAdviceBeans 中
if (RequestBodyAdvice.class.isAssignableFrom(beanType) || ResponseBodyAdvice.class.isAssignableFrom(beanType)) {
requestResponseBodyAdviceBeans.add(adviceBean);
}
}
// <2.3> 將 requestResponseBodyAdviceBeans 添加到 this.requestResponseBodyAdvice 屬性種
if (!requestResponseBodyAdviceBeans.isEmpty()) {
this.requestResponseBodyAdvice.addAll(0, requestResponseBodyAdviceBeans);
}
// 列印日志
if (logger.isDebugEnabled()) {
int modelSize = this.modelAttributeAdviceCache.size();
int binderSize = this.initBinderAdviceCache.size();
int reqCount = getBodyAdviceCount(RequestBodyAdvice.class);
int resCount = getBodyAdviceCount(ResponseBodyAdvice.class);
if (modelSize == 0 && binderSize == 0 && reqCount == 0 && resCount == 0) {
logger.debug("ControllerAdvice beans: none");
}
else {
logger.debug("ControllerAdvice beans: " + modelSize + " @ModelAttribute, " + binderSize +
" @InitBinder, " + reqCount + " RequestBodyAdvice, " + resCount + " ResponseBodyAdvice");
}
}
}
-
從 Spring 背景關系掃描
@ControllerAdvice注解的 Bean 們,生成對應的ControllerAdviceBean物件,并將進行排序,方法如下:public static List<ControllerAdviceBean> findAnnotatedBeans(ApplicationContext context) { return Arrays.stream(BeanFactoryUtils.beanNamesForTypeIncludingAncestors(context, Object.class)) // 排除代理目標類,AOP 相關 .filter(name -> !ScopedProxyUtils.isScopedTarget(name)) // 包含 @ControllerAdvice 注解 .filter(name -> context.findAnnotationOnBean(name, ControllerAdvice.class) != null) // 生成對應的 ControllerAdviceBean 物件 .map(name -> new ControllerAdviceBean(name, context)) .collect(Collectors.toList()); }@ControllerAdvice注解:用于 Controller 類的增強類,其中可定義多種增強的方法,例如@ExceptionHandler注解的方法用于處理器 Controller 拋出的例外 -
遍歷
1中生成 ControllerAdviceBean 陣列- 掃描有
@ModelAttribute,無@RequestMapping注解的方法,添加到modelAttributeAdviceCache屬性中,該類方法用于在執行方法前修改 Model 物件 - 掃描有
@InitBinder注解的方法,添加到initBinderAdviceCache屬性中,該類方法用于在執行方法前初始化資料系結器 - 如果是 RequestBodyAdvice 或 ResponseBodyAdvice 的子類,保存至 requestResponseBodyAdviceBeans 臨時變數中
- 掃描有
-
將
2.3的 requestResponseBodyAdviceBeans 保存至requestResponseBodyAdvice屬性中
1.2 getDefaultArgumentResolvers
getDefaultArgumentResolvers(),初始化默認的引數決議器,方法如下:
private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>();
// Annotation-based argument resolution
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
resolvers.add(new RequestParamMapMethodArgumentResolver());
resolvers.add(new PathVariableMethodArgumentResolver());
resolvers.add(new PathVariableMapMethodArgumentResolver());
resolvers.add(new MatrixVariableMethodArgumentResolver());
resolvers.add(new MatrixVariableMapMethodArgumentResolver());
resolvers.add(new ServletModelAttributeMethodProcessor(false));
resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters(), this.requestResponseBodyAdvice));
resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));
resolvers.add(new RequestHeaderMapMethodArgumentResolver());
resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));
resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
resolvers.add(new SessionAttributeMethodArgumentResolver());
resolvers.add(new RequestAttributeMethodArgumentResolver());
// Type-based argument resolution
resolvers.add(new ServletRequestMethodArgumentResolver());
resolvers.add(new ServletResponseMethodArgumentResolver());
resolvers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
resolvers.add(new RedirectAttributesMethodArgumentResolver());
resolvers.add(new ModelMethodProcessor());
resolvers.add(new MapMethodProcessor());
resolvers.add(new ErrorsMethodArgumentResolver());
resolvers.add(new SessionStatusMethodArgumentResolver());
resolvers.add(new UriComponentsBuilderMethodArgumentResolver());
// Custom arguments
if (getCustomArgumentResolvers() != null) {
resolvers.addAll(getCustomArgumentResolvers());
}
// Catch-all
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
resolvers.add(new ServletModelAttributeMethodProcessor(true));
return resolvers;
}
- 按順序添加了非常多的引數決議器物件
1.3 getDefaultInitBinderArgumentResolvers
getDefaultInitBinderArgumentResolvers(),初始化默認的引數系結器,方法如下:
private List<HandlerMethodArgumentResolver> getDefaultInitBinderArgumentResolvers() {
List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>();
// Annotation-based argument resolution
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
resolvers.add(new RequestParamMapMethodArgumentResolver());
resolvers.add(new PathVariableMethodArgumentResolver());
resolvers.add(new PathVariableMapMethodArgumentResolver());
resolvers.add(new MatrixVariableMethodArgumentResolver());
resolvers.add(new MatrixVariableMapMethodArgumentResolver());
resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
resolvers.add(new SessionAttributeMethodArgumentResolver());
resolvers.add(new RequestAttributeMethodArgumentResolver());
// Type-based argument resolution
resolvers.add(new ServletRequestMethodArgumentResolver());
resolvers.add(new ServletResponseMethodArgumentResolver());
// Custom arguments
if (getCustomArgumentResolvers() != null) {
resolvers.addAll(getCustomArgumentResolvers());
}
// Catch-all
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
return resolvers;
}
1.4 getDefaultReturnValueHandlers
getDefaultReturnValueHandlers(),初始化默認的回傳值處理器,方法如下:
private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {
List<HandlerMethodReturnValueHandler> handlers = new ArrayList<>();
// Single-purpose return value types
handlers.add(new ModelAndViewMethodReturnValueHandler());
handlers.add(new ModelMethodProcessor());
handlers.add(new ViewMethodReturnValueHandler());
handlers.add(new ResponseBodyEmitterReturnValueHandler(getMessageConverters(),
this.reactiveAdapterRegistry, this.taskExecutor, this.contentNegotiationManager));
handlers.add(new StreamingResponseBodyReturnValueHandler());
handlers.add(new HttpEntityMethodProcessor(getMessageConverters(),
this.contentNegotiationManager, this.requestResponseBodyAdvice));
handlers.add(new HttpHeadersReturnValueHandler());
handlers.add(new CallableMethodReturnValueHandler());
handlers.add(new DeferredResultMethodReturnValueHandler());
handlers.add(new AsyncTaskMethodReturnValueHandler(this.beanFactory));
// Annotation-based return value types
handlers.add(new ModelAttributeMethodProcessor(false));
handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(),
this.contentNegotiationManager, this.requestResponseBodyAdvice));
// Multi-purpose return value types
handlers.add(new ViewNameMethodReturnValueHandler());
handlers.add(new MapMethodProcessor());
// Custom return value types
if (getCustomReturnValueHandlers() != null) {
handlers.addAll(getCustomReturnValueHandlers());
}
// Catch-all
if (!CollectionUtils.isEmpty(getModelAndViewResolvers())) {
handlers.add(new ModelAndViewResolverMethodReturnValueHandler(getModelAndViewResolvers()));
}
else {
handlers.add(new ModelAttributeMethodProcessor(true));
}
return handlers;
}
- 按順序添加了非常多的回傳值處理器物件
supportsInternal 方法
實作 supportsInternal() 介面,方法如下:
@Override
protected boolean supportsInternal(HandlerMethod handlerMethod) {
return true;
}
直接回傳 true,也就是說處理器只要是 HandlerMethod 物件就可以
getLastModifiedInternal 方法
@Override
protected long getLastModifiedInternal(HttpServletRequest request, HandlerMethod handlerMethod) {
return -1;
}
直接回傳 -1
handleInternal 方法
實作 handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) 方法,處理請求,執行處理器,方法如下:
@Override
protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response,
HandlerMethod handlerMethod) throws Exception {
ModelAndView mav;
// <1> 校驗請求(HttpMethod 和 Session 的校驗)
checkRequest(request);
// <2> 呼叫 HandlerMethod 方法
// Execute invokeHandlerMethod in synchronized block if required.
if (this.synchronizeOnSession) { // 同步相同 Session 的邏輯,默認情況false
HttpSession session = request.getSession(false);
if (session != null) {
// 獲取Session的鎖物件
Object mutex = WebUtils.getSessionMutex(session);
synchronized (mutex) {
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
// No HttpSession available -> no mutex necessary
mav = invokeHandlerMethod(request, response, handlerMethod);
}
} else {
// No synchronization on session demanded at all...
mav = invokeHandlerMethod(request, response, handlerMethod);
}
if (!response.containsHeader(HEADER_CACHE_CONTROL)) { // 回應不包含'Cache-Control'頭
if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
}
else {
prepareResponse(response);
}
}
return mav;
}
-
呼叫父類 WebContentGenerator 的
checkRequest(ttpServletRequest request)方法,校驗請求(HttpMethod 和 Session)是否合法protected final void checkRequest(HttpServletRequest request) throws ServletException { // Check whether we should support the request method. String method = request.getMethod(); if (this.supportedMethods != null && !this.supportedMethods.contains(method)) { throw new HttpRequestMethodNotSupportedException(method, this.supportedMethods); } // Check whether a session is required. if (this.requireSession && request.getSession(false) == null) { throw new HttpSessionRequiredException("Pre-existing session required but none found"); } }在 AbstractHandlerMethodAdapter 的構造方法中,傳入
restrictDefaultSupportedMethods引數為false,表示不需要嚴格校驗 HttpMethod,這里正常情況都會校驗通過 -
呼叫
invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod)方法,執行 HandlerMethod 處理器這里會判斷
synchronizeOnSession屬性,控制是否同步相同 Session 的邏輯,其中WebUtils#getSessionMutex(session)方法,獲得用來鎖的物件,方法如下:public static Object getSessionMutex(HttpSession session) { Assert.notNull(session, "Session must not be null"); Object mutex = session.getAttribute(SESSION_MUTEX_ATTRIBUTE); if (mutex == null) { mutex = session; } return mutex; }當然,因為鎖是通過
synchronized是 JVM 行程級,所以在分布式環境下,無法達到同步相同 Session 的功能默認情況下,
synchronizeOnSession為false
【重點】invokeHandlerMethod方法
invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) 方法,執行 HandlerMethod 處理器,方法如下:
@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response,
HandlerMethod handlerMethod) throws Exception {
// <1> 創建 ServletWebRequest 物件
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
// <2> 創建 WebDataBinderFactory 物件
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
// <3> 創建 ModelFactory 物件
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
// <4> 創建 ServletInvocableHandlerMethod 物件,并設定其相關屬性
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
if (this.argumentResolvers != null) {
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
if (this.returnValueHandlers != null) {
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
}
invocableMethod.setDataBinderFactory(binderFactory);
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
// <5> 創建 ModelAndViewContainer 物件,并初始其相關屬性
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
modelFactory.initModel(webRequest, mavContainer, invocableMethod);
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
// <6> 創建 AsyncWebRequest 異步請求物件
AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
asyncWebRequest.setTimeout(this.asyncRequestTimeout);
// <7> 創建 WebAsyncManager 異步請求管理器物件
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.setTaskExecutor(this.taskExecutor);
asyncManager.setAsyncWebRequest(asyncWebRequest);
asyncManager.registerCallableInterceptors(this.callableInterceptors);
asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
// <8>
if (asyncManager.hasConcurrentResult()) {
Object result = asyncManager.getConcurrentResult();
mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
asyncManager.clearConcurrentResult();
LogFormatUtils.traceDebug(logger, traceOn -> {
String formatted = LogFormatUtils.formatValue(result, !traceOn);
return "Resume with async result [" + formatted + "]";
});
invocableMethod = invocableMethod.wrapConcurrentResult(result);
}
// <9> 執行呼叫
invocableMethod.invokeAndHandle(webRequest, mavContainer);
// <10>
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
// <11> 獲得 ModelAndView 物件
return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
// <12> 標記請求完成
webRequest.requestCompleted();
}
}
因為,Spring MVC 提供了大量的特性,所以 HandlerAdapter 又涉及許多組件,?? 我們主要先梳理好主流程,所以涉及的組件,還是先不詳細決議,我們的目的是,看到怎么呼叫 HandlerMethod 方法的,即呼叫 Controller 的 @RequestMapping 注解的方法,
-
創建 ServletWebRequest 物件,包含了
request請求和response回應 -
呼叫
getDataBinderFactory(HandlerMethod handlerMethod)方法,創建 WebDataBinderFactory 物件,有關于資料系結,暫時忽略 -
呼叫
getModelFactory(HandlerMethod handlerMethod, WebDataBinderFactory binderFactory)方法,創建 ModelFactory 物件,有關于往 Model 物件設定資料,暫時忽略 -
【核心】呼叫
createInvocableHandlerMethod(HandlerMethod handlerMethod)方法,創建 ServletInvocableHandlerMethod 物件,然后設定其屬性,本文會對 ServletInvocableHandlerMethod 做簡單的決議, 詳細的決議在《HandlerAdapter 組件(二)之 ServletInvocableHandlerMethod》中 -
創建 ModelAndViewContainer 物件,并初始其相關屬性
-
創建 AsyncWebRequest 異步請求物件,暫時忽略
-
創建 WebAsyncManager 異步請求管理器物件,暫時忽略
-
異步處理,并發結果相關,暫時忽略
-
【核心】呼叫 ServletInvocableHandlerMethod 的
invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs)方法,執行處理器,方法如下:// ServletInvocableHandlerMethod.java public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { // <1> 執行呼叫 Object returnValue = https://www.cnblogs.com/lifullmoon/archive/2020/12/17/invokeForRequest(webRequest, mavContainer, providedArgs); // <2> 設定回應狀態碼 setResponseStatus(webRequest); // <3> 設定 ModelAndViewContainer 為請求已處理,回傳,和 @ResponseStatus 注解相關 if (returnValue == null) { if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) { disableContentCachingIfNecessary(webRequest); mavContainer.setRequestHandled(true); return; } } else if (StringUtils.hasText(getResponseStatusReason())) { mavContainer.setRequestHandled(true); return; } // <4> 設定 ModelAndViewContainer 為請求未處理 mavContainer.setRequestHandled(false); Assert.state(this.returnValueHandlers != null,"No return value handlers"); try { // <5> 處理回傳值 this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest); } catch (Exception ex) { if (logger.isTraceEnabled()) { logger.trace(formatErrorForReturnValue(returnValue), ex); } throw ex; } } // InvocableHandlerMethod.java @Nullable public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { // <y> 決議引數 Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs); if (logger.isTraceEnabled()) { logger.trace("Arguments: " + Arrays.toString(args)); } // 執行呼叫 return doInvoke(args); } // InvocableHandlerMethod.java @Nullable protected Object doInvoke(Object... args) throws Exception { // <z1> 設定方法為可訪問 ReflectionUtils.makeAccessible(getBridgedMethod()); try { // <z2> 執行呼叫 return getBridgedMethod().invoke(getBean(), args); } catch (IllegalArgumentException ex) { assertTargetBean(getBridgedMethod(), getBean(), args); String text = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument"); throw new IllegalStateException(formatInvokeError(text, args), ex); } catch (InvocationTargetException ex) { // Unwrap for HandlerExceptionResolvers ... Throwable targetException = ex.getTargetException(); if (targetException instanceof RuntimeException) { throw (RuntimeException) targetException; } else if (targetException instanceof Error) { throw (Error) targetException; } else if (targetException instanceof Exception) { throw (Exception) targetException; } else { throw new IllegalStateException(formatInvokeError("Invocation failure", args), targetException); } } }可以大致過一下上面的執行邏輯,決議引數,通過反射執行方法,決議執行結果,詳細決議在后續的《HandlerAdapter 組件(二)之 ServletInvocableHandlerMethod》檔案中
-
異步處理,并發結果相關,暫時忽略
-
呼叫
getModelAndView(ModelAndViewContainer mavContainer, ModelFactory modelFactory, NativeWebRequest webRequest)方法,獲得 ModelAndView 物件,方法如下:@Nullable private ModelAndView getModelAndView(ModelAndViewContainer mavContainer, ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception { modelFactory.updateModel(webRequest, mavContainer); // 情況一,如果 mavContainer 已處理,則回傳“空”的 ModelAndView 物件, if (mavContainer.isRequestHandled()) { return null; } // 情況二,如果 mavContainer 未處理,則基于 `mavContainer` 生成 ModelAndView 物件 ModelMap model = mavContainer.getModel(); // 創建 ModelAndView 物件,并設定相關屬性 ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus()); if (!mavContainer.isViewReference()) { mav.setView((View) mavContainer.getView()); } if (model instanceof RedirectAttributes) { Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes(); HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class); if (request != null) { RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes); } } return mav; }- 情況一,如果
mavContainer已處理,則回傳“空”的 ModelAndView 物件,@ResponseBody注解的結果處理則直接回傳null - 情況二,如果
mavContainer未處理,則基于mavContainer生成 ModelAndView 物件
在后續的檔案分析中會講到,注意這里的
requestHandled屬性,到時候再回過頭來理解?? - 情況一,如果
-
標記請求完成,暫時忽略
總結
Spring MVC 通過 HandlerMapping 組件會為請求找到合適的 HandlerExecutionChain 處理器執行鏈,包含處理器(handler)和攔截器們(interceptors),其中處理器的實作有多種,例如通過實作 Controller 介面、HttpRequestHandler 介面,或者使用 @RequestMapping 注解將方法作為一個處理器等,這就導致 Spring MVC 無法直接執行這個處理器,所以這里需要一個處理器配接器,由它去執行處理器,
HandlerAdapter 處理器配接器對應的也有多種,那種配接器支持處理這種型別的處理器,則由該配接器去執行,如下:
HttpRequestHandlerAdapter:執行實作了 HttpRequestHandler 介面的處理器SimpleControllerHandlerAdapter:執行實作了 Controller 介面的處理器SimpleServletHandlerAdapter:執行實作了 Servlet 介面的處理器RequestMappingHandlerAdapter:執行 HandlerMethod 型別的處理器,也就是通過@RequestMapping等注解標注的方法
這里我們重點看 RequestMappingHandlerAdapter 物件,因為這種方式是目前使用最普遍的,其他型別的 HandlerAdapter 處理器配接器做了解即可
本文講述了 RequestMappingHandlerAdapter 處理執行器的整個流程,大致邏輯如下:
- 通過
ServletInvocableHandlerMethod(HandlerMethod處理器的封裝)物件去執行 - 需要通過
HandlerMethodArgumentResolver物件進行引數決議 - 通過反射執行對應的 Method 方法物件
- 需要通過
HandlerMethodReturnValueHandler物件對執行結果進行處理,設定到response回應中,生成對應的 ModelAndView 物件
上面涉及到的三個組件分別在后續的檔案中進行決議,先整體,后區域??
參考文章:芋道原始碼《精盡 Spring MVC 原始碼分析》
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/236379.html
標籤:其他
上一篇:演算法相關問題
