HandleAdapter
HandlerAdapter的功能实际就是执行我们的具体的Controller、Servlet或者HttpRequestHandler中的方法。
类结构如下:
1、SimpleServletHandlerAdapter实际就是执行HttpServlet的service方法
springMVC源码分析–SimpleServletHandlerAdapter(二)
2、SimpleControllerHandlerAdapter实际就是执行Controller的handleRequest方法
springMVC源码分析–SimpleControllerHandlerAdapter(三)
3、HttpRequestHandlerAdapter实际就是执行HttpRequestHandler的handleRequest方法 springMVC源码分析–HttpRequestHandlerAdapter(四)
4、RequestMappingHandlerAdapter实际就是执行@RequestMapping注解的方法。
5、AnnotationMethodHandlerAdapter已结被废弃,就不做过多介绍
该接口有3个方法
public interface HandlerAdapter {
boolean supports(Object handler);
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
long getLastModified(HttpServletRequest request, Object handler);
}
HandlerAdapter的执行操作,其执行过程在DispatcherServlet的doDispatch中,执行流程如下:
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
........
try {
try {
//获取合适的HandlerAdapter实现类
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
........
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
}
........
//执行真正的请求操作
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
........
}
HandlerAdapter处理3步
1.DispatcherServlte会根据配置文件信息注册HandlerAdapter。
如果在配置文件中没有配置,那么DispatcherServlte会获取HandlerAdapter的默认配置,
如果是读取默认配置的话,DispatcherServlte会读取DispatcherServlte.properties文件,
该文件中配置了三种HandlerAdapter:HttpRequestHandlerAdapter,SimpleControllerHandlerAdapter和AnnotationMethodHandlerAdapter。
DispatcherServlte会将这三个HandlerAdapter对象存储到它的handlerAdapters这个集合属性中,这样就完成了HandlerAdapter的注册。
2.DispatcherServlte会根据handlerMapping传过来的controller与已经注册好了的HandlerAdapter一一匹配,
看哪一种HandlerAdapter是支持该controller类型的,如果找到了其中一种HandlerAdapter是支持传过来的controller类型,
那么该HandlerAdapter会调用自己的handle方法,
handle方法运用java的反射机制执行controller的具体方法来获得ModelAndView,
例如SimpleControllerHandlerAdapter是支持实现了controller接口的控制器,如果自己写的控制器实现了controller接口,那么SimpleControllerHandlerAdapter就会去执行自己写控制器中的具体方法来完成请求。
分析handlerAdapter注册
//初始化handlerAdapters 放在一个链表中
private void initHandlerAdapters(ApplicationContext context) {
this.handlerAdapters = null;
if (this.detectAllHandlerAdapters) {
// Find all HandlerAdapters in the ApplicationContext, including ancestor contexts.
Map<String, HandlerAdapter> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerAdapters = new ArrayList<HandlerAdapter>(matchingBeans.values());
// We keep HandlerAdapters in sorted order.
OrderComparator.sort(this.handlerAdapters);
}
}
else {
try {
HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);
this.handlerAdapters = Collections.singletonList(ha);
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore, we'll add a default HandlerAdapter later.
}
}
// Ensure we have at least some HandlerAdapters, by registering
// default HandlerAdapters if no other adapters are found.
if (this.handlerAdapters == null) {
this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);
if (logger.isDebugEnabled()) {
logger.debug("No HandlerAdapters found in servlet '" + getServletName() + "': using default");
}
}
}
2.根据handlerMapping传过来的Handler对象与DispatcherServlet集合属性handlerAdapter中的HandlerAdapter一一匹配,如果有支持Handler对象的HandlerAdapter,那么HandlerAdapter就会调用自己的handle方法处理请求。
rotected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
for (HandlerAdapter ha : this.handlerAdapters) {
if (logger.isTraceEnabled()) {
logger.trace("Testing handler adapter [" + ha + "]");
}
if (ha.supports(handler)) {
return ha;
}
}
throw new ServletException("No adapter for handler [" + handler +
"]: Does your handler implement a supported interface like Controller?");
}
在运行的过程中发现SimpleControllerHandlerAdapter是支持Controller类型的控制器的。
来看一下SimpleControllerHandlerAdapter的代码
public class SimpleControllerHandlerAdapter implements HandlerAdapter {
public boolean supports(Object handler) {
return (handler instanceof Controller);
}
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return ((Controller) handler).handleRequest(request, response);
}
public long getLastModified(HttpServletRequest request, Object handler) {
if (handler instanceof LastModified) {
return ((LastModified) handler).getLastModified(request);
}
return -1L;
}
}
Controller源码,Controller接口只有一个handleRequest方法
public interface Controller {
ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception;
}
再看看实现了Controller接口的AbstractController类
public abstract class AbstractController extends WebContentGenerator implements Controller {
private boolean synchronizeOnSession = false;
/**
* Set if controller execution should be synchronized on the session,
* to serialize parallel invocations from the same client.
* <p>More specifically, the execution of the <code>handleRequestInternal</code>
* method will get synchronized if this flag is "true". The best available
* session mutex will be used for the synchronization; ideally, this will
* be a mutex exposed by HttpSessionMutexListener.
* <p>The session mutex is guaranteed to be the same object during
* the entire lifetime of the session, available under the key defined
* by the <code>SESSION_MUTEX_ATTRIBUTE</code> constant. It serves as a
* safe reference to synchronize on for locking on the current session.
* <p>In many cases, the HttpSession reference itself is a safe mutex
* as well, since it will always be the same object reference for the
* same active logical session. However, this is not guaranteed across
* different servlet containers; the only 100% safe way is a session mutex.
* @see org.springframework.web.servlet.mvc.AbstractController#handleRequestInternal
* @see org.springframework.web.util.HttpSessionMutexListener
* @see org.springframework.web.util.WebUtils#getSessionMutex(javax.servlet.http.HttpSession)
*/
public final void setSynchronizeOnSession(boolean synchronizeOnSession) {
this.synchronizeOnSession = synchronizeOnSession;
}
/**
* Return whether controller execution should be synchronized on the session.
*/
public final boolean isSynchronizeOnSession() {
return this.synchronizeOnSession;
}
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
throws Exception {
// Delegate to WebContentGenerator for checking and preparing.
checkAndPrepare(request, response, this instanceof LastModified);
// Execute handleRequestInternal in synchronized block if required.
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized (mutex) {
return handleRequestInternal(request, response);
}
}
}
return handleRequestInternal(request, response);
}
/**
* Template method. Subclasses must implement this.
* The contract is the same as for <code>handleRequest</code>.
* @see #handleRequest
*/
protected abstract ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)
throws Exception;
}
再看一下继承了AbstractController的MultiActionController,MultiActionController中有对AbstractController的handleRequestInternal的实现
protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)
throws Exception {
try {
//找寻该请求对象的方法名 推测是反射
String methodName = this.methodNameResolver.getHandlerMethodName(request);
//根据方法名返回视图
return invokeNamedMethod(methodName, request, response);
}
catch (NoSuchRequestHandlingMethodException ex) {
return handleNoSuchRequestHandlingMethod(ex, request, response);
}
}
可以看出在MultiActionController的handleRequestInternal方法中分为两步,第一步是找寻执行该请求的方法名,第二步是调用invokeNamedMethod方法。
invokeNamedMethod方法源码
protected final ModelAndView invokeNamedMethod(
String methodName, HttpServletRequest request, HttpServletResponse response) throws Exception {
//获取方法对象 来自于handlerMethodMap
Method method = this.handlerMethodMap.get(methodName);
if (method == null) {
//没有该请求方法名
throw new NoSuchRequestHandlingMethodException(methodName, getClass());
}
try {
//参数列表
Class[] paramTypes = method.getParameterTypes();
List<Object> params = new ArrayList<Object>(4);
params.add(request);
params.add(response);
if (paramTypes.length >= 3 && paramTypes[2].equals(HttpSession.class)) {
HttpSession session = request.getSession(false);
if (session == null) {
throw new HttpSessionRequiredException(
"Pre-existing session required for handler method '" + methodName + "'");
}
//session加入到params
params.add(session);
}
// If last parameter isn't of HttpSession type, it's a command.
if (paramTypes.length >= 3 &&
!paramTypes[paramTypes.length - 1].equals(HttpSession.class)) {
Object command = newCommandObject(paramTypes[paramTypes.length - 1]);
params.add(command);
//绑定
bind(request, command);
}
//执行该方法对象的invoke
Object returnValue = method.invoke(this.delegate, params.toArray(new Object[params.size()]));
//判断返回值类型
return massageReturnValueIfNecessary(returnValue);
}
catch (InvocationTargetException ex) {
// The handler method threw an exception.
return handleException(request, response, ex.getTargetException());
}
catch (Exception ex) {
// The binding process threw an exception.
return handleException(request, response, ex);
}
}
根据方法名在MultiActionController的方法集合属性handlerMethodMap中寻找对应的方法对象,然后执行该方法对象,
执行该方法对象后获得一个object的返回值,通过massageReturnValueIfNecessary方法判断这个返回值的类型,
如果这个值的返回类型是ModelAndView类型,就返回ModelAndView。到此我们找到响应请求的方法并执行获得了返回值。
虽然总体走完了。
但是有两个地方还没有说,
1如何根据用户发来的url请求来确定url中哪一段是执行该请求的方法名;
2.确定方法名后是怎么找到该方法的。
handlerMethodMap咋来的
MultiActionController中有一个构造函数,
registerHandlerMethods(this.delegate);方法就是对我们所写的controller中的方法的注册。
public MultiActionController() {
this.delegate = this;
registerHandlerMethods(this.delegate);
// We'll accept no handler methods found here - a delegate might be set later on.
}
registerHandlerMethods方法
private void registerHandlerMethods(Object delegate) {
this.handlerMethodMap.clear();
this.lastModifiedMethodMap.clear();
this.exceptionHandlerMap.clear();
// Look at all methods in the subclass, trying to find
// methods that are validators according to our criteria
Method[] methods = delegate.getClass().getMethods();
for (Method method : methods) {
// We're looking for methods with given parameters.
if (isExceptionHandlerMethod(method)) {
registerExceptionHandlerMethod(method);
}
else if (isHandlerMethod(method)) {
registerHandlerMethod(method);
registerLastModifiedMethodIfExists(delegate, method);
}
}
}
ParameterMethodNameResolver这个类的作用就是根据url链接中带的参数来确定执行该url的方法名是什么。在ioc容器初始ParameterMethodNameResolver的时候,容器会将“m”这个参数赋值给ParameterMethodNameResolver的属性paramName,然后ParameterMethodNameResolver会根据url中m后面跟的参数来获取方法名
public String getHandlerMethodName(HttpServletRequest request) throws NoSuchRequestHandlingMethodException {
String methodName = null;
// Check parameter names where the very existence of each parameter
// means that a method of the same name should be invoked, if any.
if (this.methodParamNames != null) {
for (String candidate : this.methodParamNames) {
if (WebUtils.hasSubmitParameter(request, candidate)) {
methodName = candidate;
if (logger.isDebugEnabled()) {
logger.debug("Determined handler method '" + methodName +
"' based on existence of explicit request parameter of same name");
}
break;
}
}
}
// Check parameter whose value identifies the method to invoke, if any.
if (methodName == null && this.paramName != null) {
methodName = request.getParameter(this.paramName);
if (methodName != null) {
if (logger.isDebugEnabled()) {
logger.debug("Determined handler method '" + methodName +
"' based on value of request parameter '" + this.paramName + "'");
}
}
}
if (methodName != null && this.logicalMappings != null) {
// Resolve logical name into real method name, if appropriate.
String originalName = methodName;
methodName = this.logicalMappings.getProperty(methodName, methodName);
if (logger.isDebugEnabled()) {
logger.debug("Resolved method name '" + originalName + "' to handler method '" + methodName + "'");
}
}
if (methodName != null && !StringUtils.hasText(methodName)) {
if (logger.isDebugEnabled()) {
logger.debug("Method name '" + methodName + "' is empty: treating it as no method name found");
}
methodName = null;
}
if (methodName == null) {
if (this.defaultMethodName != null) {
// No specific method resolved: use default method.
methodName = this.defaultMethodName;
if (logger.isDebugEnabled()) {
logger.debug("Falling back to default handler method '" + this.defaultMethodName + "'");
}
}
else {
// If resolution failed completely, throw an exception.
throw new NoSuchRequestHandlingMethodException(request);
}
}
return methodName;
}
当找到了方法名后,就会去MultiActionController属性handlerMethodMap中根据方法名找方法对象。再执行这个方法就好了。
HandlerAdapter,大家都叫它适配处理器,就是适配不同的处理器,将他们封装起来调用同一个接口方法,
这样DispatcherServlet就只需要调用接口方法,而不需要在DispatcherServlet判断调用哪一个具体的HandlerAdapter的实现类了。
当时看到自己项目里面的所有的处理器都是实现了MultiActionController的Controller,
再去看MultiActionController的源码时,发现MultiActionController实现了Controller接口,
Controller接口只有一个handleRequest方法,
我想DispatcherServlet直接用Controller的handleRequest方法执行具体请求就行了,何必还要用HandlerAdapter将Controller封装起来,
再在HandlerAdapter的handle方法里执行Controller的handleRequest方法呢,这不是多此一举?
只怪自己目光短浅,由于用的是配置的方式来做项目的,
而且平时自己写的Controller只继承了MultiActionController,
以为Controller接口就是所有的处理器的接口,眼里就只有Controller了。
今天再来看源码,发现处理器根本就不只有Controller这一种。
还有HttpRequestHandler,Servlet等处理器。
下面来介绍一下几种适配器对应的处理器以及这些处理器的作用\
1. AnnotationMethodHandlerAdapter主要是适配注解类处理器,注解类处理器就是我们经常使用的@Controller的这类处理器
2. HttpRequestHandlerAdapter主要是适配静态资源处理器,静态资源处理器就是实现了HttpRequestHandler接口的处理器,这类处理器的作用是处理通过SpringMVC来访问的静态资源的请求。
3.SimpleControllerHandlerAdapter是Controller处理适配器,适配实现了Controller接口或Controller接口子类的处理器,比如我们经常自己写的Controller来继承MultiActionController,那么自己写的这些Controller就会由SimpleControllerHandlerAdapter来适配
4.SimpleServletHandlerAdapter是Servlet处理适配器,适配实现了Servlet接口或Servlet的子类的处理器,我们不仅可以在web.xml里面配置Servlet,其实也可以用SpringMVC来配置Servlet,不过这个适配器很少用到,而且SpringMVC默认的适配器没有他,默认的是前面的三种。
适配处理器当然用到了适配器模式。
感觉写的像屎一样