閱讀182 返回首頁    go 小米 go 小米5


SpringMVC 遺漏補充

說到SpringMVC,一般都說Spring將請求與方法進行了映射,所以每次請求都能找到對應的方法,這次我想找到代碼層麵上是如何處理的,而不是泛泛而談。我們在springmvc啟動的時候說到,由於DispatcherServlet 實現了Servlet,因此會默認實現其init方法,我們在init方法中找到了我比較感興趣的兩個函數
(1) initHandlerMappings(context)
(2) initHandlerAdapters(context)

這兩個函數的內部實現不貼代碼了,就是將一些默認的類經常初始化到容器,供請求過來的時候進行調用。ok,這是我前幾次看完代碼得到的感悟,當時始終沒有解決我的問題,到底在什麼時候將URL與方法進行了映射?通過Debug跟蹤請求也是莫名其妙的Map裏麵就存在了映射關係,實在沒有辦法隻能反向查找,終於在 AbstractHandlerMethodMapping 這個類中找到了答案。

public abstract class AbstractHandlerMethodMapping<T> 
         extends AbstractHandlerMapping implements InitializingBean

AbstractHandlerMethodMapping 是SpringMVC默認的一個Handler,由於其實現了InitializingBean的接口,那麼在容器啟動的時候就會調用:

@Override
public void afterPropertiesSet() {
    initHandlerMethods();
}

step1:
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class)
掃描引用上下文,獲取所有的Bean

step2:
Class<?> beanType = getApplicationContext().getType(beanName);

   protected boolean isHandler(Class<?> beanType) {
    return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
           AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}

遍曆所有的Bean,篩選擁有注解Controller 或者 RequestMapping的類

step3:
進入最主要的函數體:detectHandlerMethods

protected void detectHandlerMethods(final Object handler) {

    // 獲取handler類型
    Class<?> handlerType = (handler instanceof String ? getApplicationContext().getType((String) handler) : handler.getClass());
    final Class<?> userType = ClassUtils.getUserClass(handlerType);

        //  從實體類中獲取方法(一般都是controller類)  
        //  這邊有興趣的話可以關注一下selectMethods的實現,應該會在工作中會有涉及到
        //  使用反射的方式獲所有的方法
    Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
        new MethodIntrospector.MetadataLookup<T>() {
        @Override
        public T inspect(Method method) {
            return getMappingForMethod(method, userType);
        }
    });

        for (Map.Entry<Method, T> entry : methods.entrySet()) {
        Method invocableMethod = AopUtils.selectInvocableMethod(entry.getKey(), userType);
        T mapping = entry.getValue();
        registerHandlerMethod(handler, invocableMethod, mapping);
    }
}

大致就是這樣的一個過程,感覺像是記錄的一個流水賬,哈哈

最後更新:2017-08-30 00:02:18

  上一篇:go  阿裏巴巴中台架構的業務價值思考——走進《企業IT架構轉型之道》係列1
  下一篇:go  阿裏雲服務器學生專享優惠