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