精盡Spring MVC源碼分析 - HandlerAdapter 組件(一)之 HandlerAdapter

該系列文檔是本人在學習 Spring MVC 的源碼過程當中總結下來的,可能對讀者不太友好,請結合個人源碼註釋 Spring MVC 源碼分析 GitHub 地址 進行閱讀html

Spring 版本:5.2.4.RELEASEjava

該系列其餘文檔請查看:《精盡 Spring MVC 源碼分析 - 文章導讀》react

HandlerAdapter 組件

HandlerAdapter 組件,處理器的適配器。由於處理器 handler 的類型是 Object 類型,須要有一個調用者來實現 handler 是怎麼被執行。Spring 中的處理器的實現多變,好比用戶的處理器能夠實現 Controller 接口或者 HttpRequestHandler 接口,也能夠用 @RequestMapping 註解將方法做爲一個處理器等,這就致使 Spring MVC 沒法直接執行這個處理器。因此這裏須要一個處理器適配器,由它去執行處理器git

因爲 HandlerMapping 組件涉及到的內容較多,考慮到內容的排版,因此將這部份內容拆分紅了五個模塊,依次進行分析:github

  • 《HandlerAdapter 組件(一)之 HandlerAdapter》
  • 《HandlerAdapter 組件(二)之 ServletInvocableHandlerMethod》
  • 《HandlerAdapter 組件(三)之 HandlerMethodArgumentResolver》
  • 《HandlerAdapter 組件(四)之 HandlerMethodReturnValueHandler》
  • 《HandlerAdapter 組件(五)之 HttpMessageConverter》

HandlerAdapter 組件(一)之 HandlerAdapter

先來回顧一下在 DispatcherServlet 中處理請求的過程當中哪裏使用到 HandlerMapping 組件,能夠回到《一個請求的旅行過程》中的 DispatcherServletdoDispatch 方法中看看,以下:web

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 -> RequestMappingHandlerAdapterspring

本文涉及到的內容適中,能夠先查看個人總結數組

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 接口的體系結構以下:session

沒有特別多😈 內心有點點欣慰,其中 RequestMappingHandlerAdapter 就是基於@RequestMapping 等註解的 HandlerMethod 的 HandlerMethodAdapter 實現類,名字都差很少

初始化過程

DispatcherServletinitHandlerAdapters(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");
        }
    }
}
  1. 若是「開啓」探測功能,則掃描已註冊的 HandlerAdapter 的 Bean 們,添加到 handlerAdapters 中,默認開啓,這裏會進行排序,能夠經過實現 Order 接口設置排序值

  2. 若是「關閉」探測功能,則得到 Bean 名稱爲 "handlerAdapter" 對應的 Bean ,將其添加至 handlerAdapters

  3. 若是未得到到,則得到默認配置的 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);
    }
}
  1. 調用 initControllerAdviceCache() 方法,初始化 ControllerAdvice 相關,詳情見下文

  2. 初始化 argumentResolvers 屬性,調用 getDefaultArgumentResolvers() 方法,得到默認的 HandlerMethodArgumentResolver 數組,詳情見下文

  3. 初始化 initBinderArgumentResolvers 屬性,調用 getDefaultInitBinderArgumentResolvers() 方法,得到默認的 HandlerMethodArgumentResolver 數組,詳情見下文

  4. 初始化 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");
        }
    }
}
  1. 從 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 拋出的異常

  2. 遍歷 1 中生成 ControllerAdviceBean 數組

    1. 掃描 @ModelAttribute @RequestMapping 註解的方法,添加到 modelAttributeAdviceCache 屬性中,該類方法用於在執行方法前修改 Model 對象
    2. 掃描 @InitBinder 註解的方法,添加到 initBinderAdviceCache 屬性中,該類方法用於在執行方法前初始化數據綁定器
    3. 若是是 RequestBodyAdvice 或 ResponseBodyAdvice 的子類,保存至 requestResponseBodyAdviceBeans 臨時變量中
  3. 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;
}
  1. 調用父類 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,這裏正常狀況都會校驗經過

  2. 調用 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 的功能

    默認狀況下,synchronizeOnSessionfalse

【重點】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 註解的方法。

  1. 建立 ServletWebRequest 對象,包含了 request 請求和 response響應

  2. 調用 getDataBinderFactory(HandlerMethod handlerMethod) 方法,建立 WebDataBinderFactory 對象,有關於數據綁定,暫時忽略

  3. 調用 getModelFactory(HandlerMethod handlerMethod, WebDataBinderFactory binderFactory) 方法,建立 ModelFactory 對象,有關於往 Model 對象設置數據,暫時忽略

  4. 【核心】調用 createInvocableHandlerMethod(HandlerMethod handlerMethod) 方法,建立 ServletInvocableHandlerMethod 對象,而後設置其屬性。本文會對 ServletInvocableHandlerMethod 作簡單的解析。 詳細的解析在《HandlerAdapter 組件(二)之 ServletInvocableHandlerMethod》

  5. 建立 ModelAndViewContainer 對象,並初始其相關屬性

  6. 建立 AsyncWebRequest 異步請求對象,暫時忽略

  7. 建立 WebAsyncManager 異步請求管理器對象,暫時忽略

  8. 異步處理,併發結果相關,暫時忽略

  9. 【核心】調用 ServletInvocableHandlerMethodinvokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) 方法,執行處理器,方法以下:

    // ServletInvocableHandlerMethod.java
    public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, 
                                Object... providedArgs) throws Exception {
        // <1> 執行調用
        Object returnValue = 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》文檔中

  10. 異步處理,併發結果相關,暫時忽略

  11. 調用 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 屬性,到時候再回過頭來理解😈

  12. 標記請求完成,暫時忽略

總結

Spring MVC 經過 HandlerMapping 組件會爲請求找到合適的 HandlerExecutionChain 處理器執行鏈,包含處理器(handler)和攔截器們(interceptors)。其中處理器的實現有多種,例如經過實現 Controller 接口、HttpRequestHandler 接口,或者使用 @RequestMapping 註解將方法做爲一個處理器等。這就致使 Spring MVC 沒法直接執行這個處理器,因此這裏須要一個處理器適配器,由它去執行處理器。

HandlerAdapter 處理器適配器對應的也有多種,那種適配器支持處理這種類型的處理器,則由該適配器去執行,以下:

  • HttpRequestHandlerAdapter:執行實現了 HttpRequestHandler 接口的處理器
  • SimpleControllerHandlerAdapter:執行實現了 Controller 接口的處理器
  • SimpleServletHandlerAdapter:執行實現了 Servlet 接口的處理器
  • RequestMappingHandlerAdapter:執行 HandlerMethod 類型的處理器,也就是經過 @RequestMapping 等註解標註的方法

這裏咱們重點看 RequestMappingHandlerAdapter 對象,由於這種方式是目前使用最廣泛的,其餘類型的 HandlerAdapter 處理器適配器作了解便可

本文講述了 RequestMappingHandlerAdapter 處理執行器的整個流程,大體邏輯以下:

  1. 經過 ServletInvocableHandlerMethodHandlerMethod 處理器的封裝)對象去執行
  2. 須要經過 HandlerMethodArgumentResolver 對象進行參數解析
  3. 經過反射執行對應的 Method 方法對象
  4. 須要經過 HandlerMethodReturnValueHandler 對象對執行結果進行處理,設置到 response 響應中,生成對應的 ModelAndView 對象

上面涉及到的三個組件分別在後續的文檔中進行解析,先總體,後局部😈

參考文章:芋道源碼《精盡 Spring MVC 源碼分析》

相關文章
相關標籤/搜索