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