前言
想必读了《理解SpringMVC看这一篇就够了》,你已经了解到DispatchServlet中的initStrategies()方法,初始化HandlerMapping组件,那让我们一切从这里开始吧!!!以RequestMappingHandlerMapping为例。
第一步:Spring创建HandlerMapping的Bean实例
简单了解一下,Spring创建Bean实例的过程中,在最终bean之前,如果实现了InitializingBean接口,那么就会调用afterPropertiesSet()方法。
// RequestMappingHandlerMapping重写了父类的afterPropertiesSet方法。当完成Bean之前,
// 会调用afterPropertiesSet()
@Override
public void afterPropertiesSet() {
// 调用父类的afterPropertiesSet()方法
① super.afterPropertiesSet();
}
//
public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean {
public void afterPropertiesSet() {
② initHandlerMethods();
}
protected void initHandlerMethods() {
for (String beanName : getCandidateBeanNames()) {
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
// 处理容器中的bean,如何处理呢????
③ processCandidateBean(beanName);
}
}
handlerMethodsInitialized(getHandlerMethods());
}
// 处理容器中bean的具体逻辑
protected void processCandidateBean(String beanName) {
Class<?> beanType = null;
try {
beanType = obtainApplicationContext().getType(beanName);
}
// isHandler():判断bean是否有@Controller 或者 @RequestMapping 注解
if (beanType != null && isHandler(beanType)) {
// 对加了注解的bean进行监测
④ detectHandlerMethods(beanName);
}
}
//
protected void detectHandlerMethods(Object handler) {
Class<?> handlerType = (handler instanceof String ?
obtainApplicationContext().getType((String) handler) : handler.getClass());
if (handlerType != null) {
Class<?> userType = ClassUtils.getUserClass(handlerType);
/**
获取当前Controller中所有标注了@RequestMapping的方法表Map<Method,RequestMappingInfo>。
eg:key=com.shang.controller.HelloController.hello()
value={RequestMappingInfo}
*/
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
(MethodIntrospector.MetadataLookup<T>) method -> {
try {
⑤ return getMappingForMethod(method, userType);
}
catch (Throwable ex) {
}
});
//
methods.forEach((method, mapping) -> {
Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
// 添加到MappingRegistry(映射注册表)
⑥ registerHandlerMethod(handler, invocableMethod, mapping);
});
}
}
}
复制代码
第一步的目的,先获取标注了@Controller或者@RequestMapping注解的Controller类,然后解析Controller中的所有方法,提取出标注了@RequestMapping注解的方法,得到Map<method,requestMappingInfo>集合;最后将Map集合遍历添加到MappingRegistry(映射注册表),映射注册表才是我们最终需要的答案。
第二步:获取所有实现HandlerMapping接口的Bean实例
private List<HandlerMapping> handlerMappings; // 存放所有的HandlerMapping
private void initHandlerMappings(ApplicationContext context) {
// detectAllHandlerMappings默认值为true,程序员可手动设置
if (this.detectAllHandlerMappings) {
// 在所有容器(包括父容器)中查找所有实现HandlerMapping接口的实现类。
Map<String, HandlerMapping> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
if (!matchingBeans.isEmpty()) {
// 赋值排序
this.handlerMappings = new ArrayList<>(matchingBeans.values());
AnnotationAwareOrderComparator.sort(this.handlerMappings);
}
}
else {
try {
// 从容器中获取beanName="handlerMapping"的Bean实例,赋值给 handlerMappings
HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
this.handlerMappings = Collections.singletonList(hm);
}
}
// 如果开发人员没有配置HandlerMapping,那么就从DispatcherServlet.properties文件中
// 加载默认的HandlerMapping。
if (this.handlerMappings == null) {
// 此方法中有很多好用的工具类,可以看一看
this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
}
}
复制代码
最终目的:获取容器(包括所有父容器)中的HandlerMapping的实现类,添加到List<HandlerMapping>,以供使用。
第三步:使用HandlerMapping的Bean实例
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.java
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// 根据request获取最合适的HandlerMethod,什么是最合适呢???
Object handler = getHandlerInternal(request);
// 根据request获取所有匹配的拦截器,最终与handler method组成一个HandlerExecutionChain
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
return executionChain;
}
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
// new HandlerExecutionChain对象,一般是原生handler
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
if (interceptor instanceof MappedInterceptor) {
MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
if (mappedInterceptor.matches(request)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
}
else {
chain.addInterceptor(interceptor);
}
}
return chain;
}
复制代码
目的之一:获取最合适的HandlerMethod。
@RequestMapping(value = "/hello", method = {RequestMethod.POST})
public String hello3() {
return "hello";
}
@RequestMapping(value = "/hello", method = {RequestMethod.GET})
public String hello4() {
return "hello";
}
复制代码
以上两个都是/hello请求,映射注册表中,pathLookup和nameLookup中,ArrayList的size为2。
当浏览器请求/hello时,如何抉择呢?最合适还是需要通过RequestMappingInfo来决定。比如,先比较value,再比较method...当然RequestMappingInfo参数远远不仅仅这两个。
目的之二:获取HandlerExecutionChain
将Handler Method 和 HandlerInterceptor 封装成HandlerExecutionChain,供DispatchServlet使用。




近期评论