SpringMVC源碼學習

1. SpringMVC重要組件

1. DispatcherServlet

SpringMVC的中央Servlet,所有請求的入口,重寫了doService()方法。核心方法:doService()、doDispatch()。

2. HandlerMapping

處理器映射,負責根據HttpServletRequest找到對應的Handler,這裏返回Handler的輔助類HandlerExecutionChain。

public interface HandlerMapping {

    @Nullable
    HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;

}

3. HandlerExecutionChain

Handler execution chain, consisting of handler object and any handler interceptors.

處理器執行鏈,Handler輔助類,由Handler對象和一些HandlerInterceptor組成,主要功能爲執行攔截器,核心屬性和方法:

    private final Object handler;

    private HandlerInterceptor[] interceptors;

    // 一般情況下返回的是一個HandlerMethod對象
    Object getHandler()

    boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response)

    void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv)

4. HandlerMethod

Encapsulates information about a handler method consisting of a method and a bean. Provides convenient access to method parameters, the method return value, method annotations, etc.

保存了Controller Bean對象和對應的Method對象。

    // 對應的Controller實例
    private final Object bean;

    // 處理請求的方法
    private final Method method;

    // 方法的參數
    private final MethodParameter[] parameters;

5. HandlerInterceptor

攔截器,自定義攔截器實現此接口。preHandle()和postHandle()方法分別在實際的請求處理之前和之後執行。

public interface HandlerInterceptor {

    default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        return true;
    }

    default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
            @Nullable ModelAndView modelAndView) throws Exception {
    }

    default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
            @Nullable Exception ex) throws Exception {
    }

}

6. HandlerAdapter

處理器適配器。handle()方法負責執行實際的請求處理並返回一個ModelAndView對象。

public interface HandlerAdapter {

    boolean supports(Object handler);

    ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;

    long getLastModified(HttpServletRequest request, Object handler);
}

2. SpringMVC請求處理流程

  1. DispatcherServlet作爲入口且重寫了doService()方法,所以請求會首先到doService()方法。下面步驟1、2、3在doService()方法完成,接着doService()方法調用doDispatch()方法,doDispatch()方法完成剩下的所有步驟。
  2. WebApplicationContext對象綁定到Request,key爲DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE。
  3. locale resolver綁定到Request。
  4. theme resolver綁定到Request。
  5. 如果是multipart request,包裝成MultipartHttpServletRequest。
  6. 調用HandlerMapping的getHandler()方法獲取對應的Handler,這裏是HandlerExecutionChain對象。
  7. 調用HandlerExecutionChain的getHandler()方法,這裏返回HandlerMethod對象,根據Handler獲取HandlerAdapter。
  8. 如果是GET或者HEAD方法執行HandlerAdapter的getLastModified()方法。
  9. 調用HandlerExecutionChain的applyPreHandle()方法執行HandlerInterceptor的preHandle()方法。
  10. 調用HandlerAdapter的handle()方法執行實際的請求處理,實際執行HandlerMethod的對應方法,返回ModelAndView對象,
  11. 根據ModelAndView視圖解析器找到對應的View。
  12. 渲染視圖返回用戶。

3. HandlerMethod收集

請求處理流程中的第5步中提到了HandlerMapping,這個核心第實現是RequestMappingHandlerMapping類,當使用SpringMVC時此類就會被注入到spring容器中,此類實現了InitializingBean接口,所以在實例化過程中會執行afterPropertiesSet()方法,此方法調用initHandlerMethods(),這個方法負責收集HandlerMethod,其相關源碼如下:

    /**
     * Detects handler methods at initialization.
     * @see #initHandlerMethods
     */
    @Override
    public void afterPropertiesSet() {
        initHandlerMethods();
    }

    /**
     * Scan beans in the ApplicationContext, detect and register handler methods.
     * @see #getCandidateBeanNames()
     * @see #processCandidateBean
     * @see #handlerMethodsInitialized
     */
    protected void initHandlerMethods() {
        // 1. 遍歷所有beanName
        for (String beanName : getCandidateBeanNames()) {
            if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
                processCandidateBean(beanName);
            }
        }
        handlerMethodsInitialized(getHandlerMethods());
    }

    /**
     *  2. 判斷beanName對應的Class是否爲Controller
     */
    protected void processCandidateBean(String beanName) {
        Class<?> beanType = null;
        try {
            beanType = obtainApplicationContext().getType(beanName);
        }
        catch (Throwable ex) {
            // An unresolvable bean type, probably from a lazy bean - let's ignore it.
            if (logger.isTraceEnabled()) {
                logger.trace("Could not resolve type for bean '" + beanName + "'", ex);
            }
        }
        // 3. 判斷邏輯爲是否有@Controller或@RequestMapping註解
        if (beanType != null && isHandler(beanType)) {
            // 檢測Controller類中的HandlerMethod
            detectHandlerMethods(beanName);
        }
    }

    @Override
    protected boolean isHandler(Class<?> beanType) {
        // 判斷邏輯爲是否有@Controller或@RequestMapping註解
        return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
                AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
    }

    protected void detectHandlerMethods(Object handler) {
        Class<?> handlerType = (handler instanceof String ?
                obtainApplicationContext().getType((String) handler) : handler.getClass());

        if (handlerType != null) {
            Class<?> userType = ClassUtils.getUserClass(handlerType);

            // 4. 檢測到所有Method
            Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
                    (MethodIntrospector.MetadataLookup<T>) method -> {
                        try {
                            return getMappingForMethod(method, userType);
                        }
                        catch (Throwable ex) {
                            throw new IllegalStateException("Invalid mapping on handler class [" +
                                    userType.getName() + "]: " + method, ex);
                        }
                    });
            if (logger.isTraceEnabled()) {
                logger.trace("Mapped " + methods.size() + " handler method(s) for " + userType + ": " + methods);
            }

            // 5. 對檢測到到Method進行註冊緩存。
            methods.forEach((method, mapping) -> {
                Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
                // 這裏把解析出到HanderMethod對象進行組冊
                registerHandlerMethod(handler, invocableMethod, mapping);
            });
        }
    }

    protected void registerHandlerMethod(Object handler, Method method, T mapping) {
        // 6. 這裏組冊到MappingRegistry的對應的集合中緩存起來
        this.mappingRegistry.register(mapping, handler, method);
    }

相關類圖:
image

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章