Spring MVC源碼閱讀

MVC的自動加載

@Configuration
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
// WebMvcConfigurationSupport這個Bean不存在纔會啓動 這個類的做用是若是@EnableWebMvc註解的自動裝配 兩個是互斥的
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
//優先級
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
//這些自動配置加載以後加載
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,
        ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {
    
}

功能是java

  1. 啓動spring.mvc和spring.resources開頭的配置項
  2. 加載InternalResourceViewResolver 內部試圖資源解析器 我理解指定JSP位置的
  3. 加載BeanNameViewResolver 支持經過BeanName匹配的視圖解析器
  4. RequestMappingHandlerAdapter 適配器 註解功能的Controller適配器
  5. RequestMappingHandlerMapping 處理請求路徑和controller對應關係的
  6. WelcomePageHandlerMapping
  7. FormattingConversionService
  8. Validator
  9. ContentNegotiationManager

handlerMapping 處理請求和controller直接的關係
handlerAdapter 處理請求和各類controller的適配問題. 好比適配servlet 普通controller 或者註解controller.
ViewResolver 視圖解析器
HandlerInterceptor 攔截器spring

HandlerInterceptor接口

  • preHandle是在找處處理handler對象的HandlerMapping以後,HandlerAdapter調度handler以前執行。
  • postHandle是在HandlerAdapter調度handler以後,DispatcherServlet渲染視圖以前執行,能夠經過ModelAndView來向視圖中添加一些信息等。
  • afterCompletion是在渲染視圖結束後執行,主要能夠用來進行過後的資源清理。

HandlerExecutionChain類

這個類由一個handler和若干的HandlerInterceptor構成。那麼這個類的做用就顯而易見了,就是將攔截器和handle組合起來執行。就是對handle進行了包裝。安全

public class HandlerExecutionChain {


    boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HandlerInterceptor[] interceptors = getInterceptors();
        if (!ObjectUtils.isEmpty(interceptors)) {
            // 順序執行
            for (int i = 0; i < interceptors.length; i++) {
                HandlerInterceptor interceptor = interceptors[i];
                // 直到遇到一個false的
                if (!interceptor.preHandle(request, response, this.handler)) {
                    // false 就執行triggerAfterCompletion
                    triggerAfterCompletion(request, response, null);
                    return false;
                }
                // 記錄false的位置
                this.interceptorIndex = i;
            }
        }
        return true;
    }

    /**
     * Apply postHandle methods of registered interceptors.
     */
    void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
            throws Exception {

        HandlerInterceptor[] interceptors = getInterceptors();
        if (!ObjectUtils.isEmpty(interceptors)) {
            for (int i = interceptors.length - 1; i >= 0; i--) {
                HandlerInterceptor interceptor = interceptors[i];
                interceptor.postHandle(request, response, this.handler, mv);
            }
        }
    }

    /**
     * Trigger afterCompletion callbacks on the mapped HandlerInterceptors.
     * Will just invoke afterCompletion for all interceptors whose preHandle invocation
     * has successfully completed and returned true.
     */
    void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex)
            throws Exception {

        HandlerInterceptor[] interceptors = getInterceptors();
        if (!ObjectUtils.isEmpty(interceptors)) {
            // 從false的位置開始. 向前遍歷順序執行. 
            for (int i = this.interceptorIndex; i >= 0; i--) {
                HandlerInterceptor interceptor = interceptors[i];
                try {
                    interceptor.afterCompletion(request, response, this.handler, ex);
                }
                catch (Throwable ex2) {
                    logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
                }
            }
        }
    }

}

MappedInterceptor接口

public final class MappedInterceptor implements HandlerInterceptor {
    @Nullable
    private final String[] includePatterns;

    @Nullable
    private final String[] excludePatterns;

    private final HandlerInterceptor interceptor;

    @Nullable
    private PathMatcher pathMatcher;

public boolean matches(String lookupPath, PathMatcher pathMatcher) {
        PathMatcher pathMatcherToUse = (this.pathMatcher != null ? this.pathMatcher : pathMatcher);
        if (!ObjectUtils.isEmpty(this.excludePatterns)) {
            for (String pattern : this.excludePatterns) {
                if (pathMatcherToUse.match(pattern, lookupPath)) {
                    return false;
                }
            }
        }
        if (ObjectUtils.isEmpty(this.includePatterns)) {
            return true;
        }
        for (String pattern : this.includePatterns) {
            if (pathMatcherToUse.match(pattern, lookupPath)) {
                return true;
            }
        }
        return false;
    }

}

true 攔截 false 不攔截併發

若是路徑在excludePatterns中,則不攔截。若是不在,那麼若includePatterns爲空,則攔截,不然在includePatterns中才攔截。mvc

比較關鍵的兩個地方是:app

  1. 優先判excludePatterns
  2. 若includePatterns列表爲空且請求不在excludePatterns的狀況下所有攔截,不然只攔截includePatterns中的內容

HandlerMapping接口

HandlerMapping是用來處理請求與handler對象的對應關係的。cors

HandlerMapping主要包含getHandler這個方法。ide

HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
DispatcherServlet就是經過調用HandlerMapping的getHandler來進行找到request對應的handler的。post

RequestMappingHandlerMapping#afterPropertiesSet()

這個方法是在項目啓動建立Bean的時候調用的. 由於他實現了InitializingBean接口.
AbstractHandlerMethodMapping#afterPropertiesSet()->initHandlerMethods()ui

protected void initHandlerMethods() {
        for (String beanName : getCandidateBeanNames()) {
            if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
                processCandidateBean(beanName);
            }
        }
        handlerMethodsInitialized(getHandlerMethods());
    }

    protected String[] getCandidateBeanNames() {
        return (this.detectHandlerMethodsInAncestorContexts ?
                BeanFactoryUtils.beanNamesForTypeIncludingAncestors(obtainApplicationContext(), Object.class) :
                obtainApplicationContext().getBeanNamesForType(Object.class));
    }
    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);
            }
        }
        //判斷是否Handler 標註了@Controller或者@RequestMapping
        if (beanType != null && isHandler(beanType)) {
            //解析controller的方法並註冊
            detectHandlerMethods(beanName);
        }
    }
    
    @Override
    protected boolean isHandler(Class<?> beanType) {
        return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
                AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
    }

    protected void detectHandlerMethods(Object handler) {
        //獲取到controller的class
        Class<?> handlerType = (handler instanceof String ?
                obtainApplicationContext().getType((String) handler) : handler.getClass());

        if (handlerType != null) {
            Class<?> userType = ClassUtils.getUserClass(handlerType);
            // 完成了controller中方法和RequestMappingInfo的綁定. 例如TestController類中的 tet方法 請求路徑信息的綁定
            //RequestMappingInfo 表明了請求的一些信息 如:路徑信息(/test/get)  method(GET)
            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(formatMappings(userType, methods));
            }
            methods.forEach((method, mapping) -> {
                Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
                //經過MappingRegistry#registry()方法註冊. 
                registerHandlerMethod(handler, invocableMethod, mapping);
            });
        }
    }

obtainApplicationContext().getBeanNamesForType(Object.class); 這個方法. 調用鏈是
AbstractApplicationContext#getBeanNamesForType(Object.class) -> DefaultListableBeanFactory#getBeanNamesForType(type, true(包含非單例的), true(包含提前加載的)); ->
DefaultListableBeanFactory#doGetBeanNamesForType() 從DefaultListableBeanFactory中定義的註冊表中獲取 type爲Object的類名字. 固然包含Controller.

通過這些全部的controller就都解析完成了.

registerHandlerMethod(handler, invocableMethod, mapping) controller的註冊

protected void registerHandlerMethod(Object handler, Method method, T mapping) {
        this.mappingRegistry.register(mapping, handler, method);
    }

handler 值是Controller的名字. 也就是beanName. spring ioc容器中註冊的名字. 若是你沒有改過, 類的第一個字母小寫. 例如TestController. handler = testController.
invocableMethod 是能夠執行的method方法. 標記了@RequestMapping註解的
mapping RequestMappingInfo類 一個請求和handler 說使用的信息. 都在這裏. 什麼狀況路徑啊 方法啊 參數啊 header啊

handler和mapping的註冊, 內部調用了MappingRegistry類. 顧名思義. 內部持有4個註冊表和一個讀寫鎖. 這個讀寫鎖就是Controller在併發環境下 線程安全的關鍵

class MappingRegistry {

        private final Map<T, MappingRegistration<T>> registry = new HashMap<>();
        //RequestMappingInfo和HandlerMethod的映射關係. LinkedHashMap<> 可以保存插入順序的和遍歷順序一致的HashMap
        private final Map<T, HandlerMethod> mappingLookup = new LinkedHashMap<>();
        //url(路徑的所有  包含Controller和方法上的path))和mappinginfo 映射關係
        private final MultiValueMap<String, T> urlLookup = new LinkedMultiValueMap<>();
        //類名字中提取大寫的字母及其執行方法的名字    例如TestController和要執行的方法名稱爲tet. 是方法名不是url 那麼這個key=TC#tet. 
        private final Map<String, List<HandlerMethod>> nameLookup = new ConcurrentHashMap<>();

        private final Map<HandlerMethod, CorsConfiguration> corsLookup = new ConcurrentHashMap<>();
        //讀寫鎖 提供讀寫效率並能保證線程安全
        private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();

        public void register(T mapping, Object handler, Method method) {
            this.readWriteLock.writeLock().lock();
            try {
                //HandlerMethod類 就是將 beanName和BeanFactory以及要執行的method封裝成了不可變對象. 用於數據傳輸和記錄信息
                HandlerMethod handlerMethod = createHandlerMethod(handler, method);
                //驗證RequestMappingInfo(不可變類)是否已經註冊過了而且仍是惟一的. 
                assertUniqueMethodMapping(handlerMethod, mapping);
                // 註冊RequestMappingInfo和HandlerMethod的映射
                this.mappingLookup.put(mapping, handlerMethod);
                // 註冊URL和mapping 信息
                List<String> directUrls = getDirectUrls(mapping);
                for (String url : directUrls) {
                    this.urlLookup.add(url, mapping);
                }

                String name = null;
                if (getNamingStrategy() != null) {
                    name = getNamingStrategy().getName(handlerMethod, mapping);
                    //nameLookup註冊
                    addMappingName(name, handlerMethod);
                }
                // 處理CrossOrigin註解
                CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
                if (corsConfig != null) {
                    this.corsLookup.put(handlerMethod, corsConfig);
                }
                // MappingRegistration不可變類, 將RequestMappingInfo HandlerMethod directUrls(/test/get) name(TC#tet)封裝. 
                this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name));
            }
            finally {
                this.readWriteLock.writeLock().unlock();
            }
        }
}

Controller的寫是有讀寫鎖保護的.

執行也能夠稱之爲請求時處理請求和Controller.

DispatcherServlet#doDispatch 扎到了這樣的代碼

// Determine handler for the current request.
                HandlerExecutionChain mappedHandler = getHandler(processedRequest);
                if (mappedHandler == null) {
                    noHandlerFound(processedRequest, response);
                    return;
                }
    @Nullable
    protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        if (this.handlerMappings != null) {
            for (HandlerMapping mapping : this.handlerMappings) {
                HandlerExecutionChain handler = mapping.getHandler(request);
                if (handler != null) {
                    return handler;
                }
            }
        }
        return null;
    }

//AbstractHandlerMapping
    public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        Object handler = getHandlerInternal(request);
        if (handler == null) {
            handler = getDefaultHandler();
        }
        if (handler == null) {
            return null;
        }
        // Bean name or resolved handler?
        if (handler instanceof String) {
            String handlerName = (String) handler;
            handler = obtainApplicationContext().getBean(handlerName);
        }

        HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);

        if (logger.isTraceEnabled()) {
            logger.trace("Mapped to " + handler);
        }
        else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
            logger.debug("Mapped to " + executionChain.getHandler());
        }

        if (CorsUtils.isCorsRequest(request)) {
            CorsConfiguration globalConfig = this.corsConfigurationSource.getCorsConfiguration(request);
            CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
            CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
            executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
        }

        return executionChain;
    }

    @Override
    protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
        String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
        this.mappingRegistry.acquireReadLock();
        try {
            HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
            return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
        }
        finally {
            this.mappingRegistry.releaseReadLock();
        }
    }

handlerMappings這是一個集合. 裏面存放着全部HeadlerMapping. 問題是這些HM什麼時候初始化的呢. 咱們都知道DispatcherServlet是本質是Servlet. 那麼Servlet聲明週期分 init(初始化)) service(執行邏輯) destroy(銷燬)

handlerMappings屬性的初始化必定和這個有關. DispatcherServlet類的初始化是經過Spring自動裝載完成的. init方法會去加載 在經過mappingRegistry讀取Handler的時候. 也是會加讀鎖的.

HandlerAdapter接口

在springMVC的執行流行流程中,當執行完handlerMapping獲取到request對應的HandlerExecutionChain以後,下一步就是調用HandlerAdapter執行對應的Handler。

public interface HandlerAdapter {

   boolean supports(Object handler);

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

   long getLastModified(HttpServletRequest request, Object handler);

}

supports()是用來判斷一個handler是否屬於該HandlerAdapter的,一個典型的實現方式是判斷該handler的類型,一般來講一個HandlerAdapter只支持一種類型的handler。

handle()的做用是使用給定的handler去處理請求。

getLastModified()的做用和HttpServlet中的getLastModified一致,如果handler不支持getLastModified則直接返回-1。

相關文章
相關標籤/搜索