springソース—四、MVC

7786 ワード

スプリングmvcはどうやって実現しますか?なぜ私たちは方法に注釈を書くだけで、httpを通じてこのインターフェースにアクセスできますか?この二つの問題を3つの部分に分けて解いてみます. : spring4.3.2
  • spring mvc全体の流れ
  • HandlerMapping
  • HandlerAdapter
  • spring mvc全体の流れ
    私達はspringを見てhttp要求を処理する過程で大体分かります.
    Spring mvcの入り口がDispactch Servletです.このservletに渡してくださいと要請した後、doDisplatchを呼び出してこの要求を配布しました.主にいくつかのことをしました.
  • multiiplet要求を処理して、ファイルのアップロードなどの要求があれば、先にDefault MultiiprtHttpServletRequest
  • にカプセル化します.
  • は、要求を処理するhandlerMappingからhandlerを取得し、HandlerExecution Chinを構築し、すべてのinterceptr
  • に入る.
  • handlerによって、すべてのHandlerAdapterからこのhanderを処理できるadapper
  • が見つかりました.
  • すべてのinterceptor.prehandle方法を実行する
  • Request Mappingの注釈が書かれている方法を呼び出し、ModelAndView
  • に戻る.
  • すべてのinterceptor.postHandle方法を実行する
  • 解析view
  • レンダーは、モデルをレスポンスに変換して
  • に戻る.
  • すべてのinterceptor.afterCompration
  • を実行します.
  • cleanupumltipad
  • 上の流れから分かるように、処理の過程では主にいくつかのキーコンポーネントが対応するロジックを完成しました.
    HandlerMapping
    Displatch Servletコンポーネントの一つとして、その中の一つがfieldです.
    org.springframework.web.servlet.DispatcherServlet#handlerMappings
    主な役割はurlからControllerへのマッピングを維持し、urlによって対応するControllerを見つけることです.
    どのようなHandlerMappingがありますか?
    springはどのようにすべてのHandlerMappingを調べますか?Displatch Servlet初期化時にこのフィールドを検索して初期化するものです.
    // org.springframework.web.servlet.DispatcherServlet#initHandlerMappings
    private void initHandlerMappings(ApplicationContext context) {
        this.handlerMappings = null;
    
        if (this.detectAllHandlerMappings) {
            // Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
            //         HandlerMapping   bean
            Map matchingBeans =
                BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
            if (!matchingBeans.isEmpty()) {
                this.handlerMappings = new ArrayList(matchingBeans.values());
                // We keep HandlerMappings in sorted order.
                AnnotationAwareOrderComparator.sort(this.handlerMappings);
            }
        }
        else {
            try {
                HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
                this.handlerMappings = Collections.singletonList(hm);
            }
            catch (NoSuchBeanDefinitionException ex) {
                // Ignore, we'll add a default HandlerMapping later.
            }
        }
    
        // Ensure we have at least one HandlerMapping, by registering
        // a default HandlerMapping if no other mappings are found.
        if (this.handlerMappings == null) {
            this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
            if (logger.isDebugEnabled()) {
                logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");
            }
        }
    }
    どのようなHandlerMappingタイプのbeanが容器にありますか?私たちがRequest Mappingを使用するなら、xmlに以下の配置が必要です.
    spring解析というラベルは
    org.springframework.web.servlet.config.AnnotationDrivenBeanDefinitionParser
    このクラスの解析xmlタグは容器にRequest MappingHandlerMappingを登録します.この類はHandlerMappingから継承されます.
    もし私たちが配置を行ったら
    このタブの使用はspring解析です.
    org.springframework.web.servlet.config.DefaultServletHandlerBeanDefinitionParser
    解析時のspringはDefault ServletHttpRequest HandlerとSimpleUrlhandler Mappingを容器に注入します.
    では
  • BenNamehandlerMapping
  • Default AnnotationHandlerMapping
  • このような場合にはこの3つのHandlerMappingタイプのbeanがあり、springはhanderMappingsを巡回して、request pathによって対応するhandlerを検索します.
    HandlerMappingはurlからhandlerまでのマッピング関係をどう管理しますか?
    HandlerMapping抽象類Abstracthandler MethodMappingの中にfieldがあります.
    // org.springframework.web.servlet.handler.AbstractHandlerMethodMapping
    private final MappingRegistry mappingRegistry = new MappingRegistry();
    このクラスはurlからhandlerまでのマッピングを維持するために使われています.このクラスにはどのようなデータ構造がありますか?
    // org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.MappingRegistry
    //    mapping      map 
    private final Map mappingLookup = new LinkedHashMap();
    //      (     org.springframework.util.AntPathMatcher#isPattern)       map 
    private final MultiValueMap urlLookup = new LinkedMultiValueMap();
    //   name handler
    private final Map> nameLookup =
        new ConcurrentHashMap>();
    // cors mapping
    private final Map corsLookup =
    mappingを登録する過程は、上記の対応するデータ構造に、Request MappingHandlerMappingを例にとって、具体的に登録するタイミングはRequest MappingHandlerMapping beanを初期化する時で、spring容器は初期化が完了したら、容器の中のeagere initのbeanを初期化します.最後にAbstracthandler MethodMappingを呼び出します.容器の中のbeanを全部探しに来ます.
  • 容器の中の全てのbean
  • を見つけました.
  • 各beanに対して中にmappingがありますか?
    inithandler Methodsメソッドを呼び出した時に容器の中の全てのbeanを取り出し、ishandlerでhandlerかどうかを判断します.実は、ControllerまたはRequest Mappingの注釈があるかどうかを判断します.
    protected boolean isHandler(Class> beanType) {
        return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
                AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
    }
    種類を見つけたら、中の方法を探します.方法の検索ロジックは方法にRequest Mappingがありますか?
    private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
        //       RequestMapping  
        RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);
        RequestCondition> condition = (element instanceof Class> ?
                                         getCustomTypeCondition((Class>) element) : getCustomMethodCondition((Method) element));
        return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null);
    }
    対応方法を見つけたら、MappingRegistryにmappingとして登録します.
    public void register(T mapping, Object handler, Method method) {
        this.readWriteLock.writeLock().lock();
        try {
            HandlerMethod handlerMethod = createHandlerMethod(handler, method);
            assertUniqueMethodMapping(handlerMethod, mapping);
    
            if (logger.isInfoEnabled()) {
                logger.info("Mapped \"" + mapping + "\" onto " + handlerMethod);
            }
            //    mapping    mappingLookup
            this.mappingLookup.put(mapping, handlerMethod);
    
            List directUrls = getDirectUrls(mapping);
            //        (   ,        ) url   urlLookup
            for (String url : directUrls) {
                this.urlLookup.add(url, mapping);
            }
    
            String name = null;
            if (getNamingStrategy() != null) {
                name = getNamingStrategy().getName(handlerMethod, mapping);
                addMappingName(name, handlerMethod);
            }
    
            CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
            if (corsConfig != null) {
                this.corsLookup.put(handlerMethod, corsConfig);
            }
    
            this.registry.put(mapping, new MappingRegistration(mapping, handlerMethod, directUrls, name));
        }
        finally {
            this.readWriteLock.writeLock().unlock();
        }
    }
    urlによってhandlerを検索する時、url Look upを優先的に探して、ワイルドカードがないのがマッチングできるかどうかを見てください.直接マッチングしていないなら、mappingLook upの中から探します.
    HandlerAdapter
    HandlerAdapterは、パラメータ解析などのDispactch Servletに対してinvokeプロセスの詳細を遮断するためである.
    Displatch Servlet初期化の時にinithanderAdaptersを呼び出して、中で容器の中のすべてのhandler Adapter実現類を探して、容器の中のhanderAdapterはmvcラベルを解析する時に容器に入れます.
    締め括りをつける
    この文章はspringを通じて一回の要求の過程を処理して、springmvcがどのように働いているかということと、その中の二つの重要なコンポーネント、HandlerMappingとHandlerAdapterを理解しました.