相信看了前边的文章,心理总是会有一些困惑。控制器Handler到底是个什么呢?首先我们可以确定的是它是一个Object对象。其次,它允许是String类型,允许是Spring Bean,允许是HandlerExecutionChain。到底是什么,取决于处于哪个阶段。
源码中第一次出现handler是在AbstractHandlerMapping类的getHandler()方法中,代码如下:
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
Object handler = getHandlerInternal(request);
if (handler == null) {
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = getApplicationContext().getBean(handlerName);
}
return getHandlerExecutionChain(handler, request);
}
getHandlerInternal()方法来得到我们想要的handler。它有三处实现,分别是:
第一个实现在AbstractHandlerMethodMapping类中,代码如下:
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
//根据请求url得到handler的查找路径
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
//根据handler的路径找到一个HandlerMethod
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
可以看到,返回值是HandlerMethod类型的。是不是有点看不懂了?没关系,我们看看HandlerMethod 类的构造方法:
public HandlerMethod(Object bean, Method method) {
this.bean = bean;
this.beanFactory = null;
this.method = method;
this.bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
this.parameters = initMethodParameters();
}
也就是说,所谓的handler在这里,是指包含了我们请求的Controller类和Method方法的对象。如此,都说的通了。难怪DispatcherServlet类中可以用适配器来调用我们的Controller层方法!
我们再来看看handlerMethod.createWithResolvedBean() 方法是个啥,上代码:
public HandlerMethod createWithResolvedBean() {
Object handler = this.bean;
if (this.bean instanceof String) {
String beanName = (String) this.bean;
handler = this.beanFactory.getBean(beanName);
}
return new HandlerMethod(this, handler);
}
熟悉不熟悉?惊喜不惊喜?可以比较一下AbstractHandlerMapping类的getHandler()方法中的代码和此处的代码,做了一件同样的事,将String类型的handler作为BeanName来得到对应的Bean对象。
第一个实现在AbstractURLHandlerMapping类中,代码如下:
protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
Object handler = lookupHandler(lookupPath, request);
return handler;
}
protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {
// Direct match?
Object handler = this.handlerMap.get(urlPath);
if (handler != null) {
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = getApplicationContext().getBean(handlerName);
}
validateHandler(handler, request);
return buildPathExposingHandler(handler, urlPath, urlPath, null);
}
}
Handler的注册中提到过handlerMap这个东西,
this.handlerMap.put(urlPath, resolvedHandler);
到这里,就结束了。需要注意的是方法的最后调用了buildPathExposingHandler()方法,实现代码如下:
protected Object buildPathExposingHandler(Object rawHandler, String bestMatchingPattern,
String pathWithinMapping, Map<String, String> uriTemplateVariables) {
HandlerExecutionChain chain = new HandlerExecutionChain(rawHandler);
chain.addInterceptor(new PathExposingHandlerInterceptor(bestMatchingPattern, pathWithinMapping));
if (!CollectionUtils.isEmpty(uriTemplateVariables)) {
chain.addInterceptor(new UriTemplateVariablesHandlerInterceptor(uriTemplateVariables));
}
return chain;
}
可以看出,最后返回了一个HandlerExecutionChain 类型的handler;
第一个实现在EmptyHandlerMapping类中,代码如下:
protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
return null;
}
这种情况下,返回值是空的,所以直接使用默认handler了。
那么问题来了,handler到底是什么呢?它是对Controller的Bean本身和请求Method的包装。而HandlerExecutionChain 是handler的二次包装,将handler与拦截器链关联到了一起。然后,在DispatcherServlert中完成了拦截器链对handler的过滤。
补充:一直在疑惑为什么只要被@Controller注解标注的Controller类就可以作为SpringMVC的请求处理类,它是怎么发挥作用的呢?这是因为@Controller注解继承了@Component注解,所以被@Controller注解标注的类会被Spring容器扫描并注册到容器中。至于真正发挥作用,就在于下面这段关键性的代码了:
if (this.bean instanceof String) {
String beanName = (String) this.bean;
handler = this.beanFactory.getBean(beanName);
}