在贴源码之前先说一下HandlerAdapter处理的大体流程,这样就有一个大体的掌握。大体流程有三步:
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就会去执行自己写控制器中的具体方法来完成请求。
下面是我自己写的代码。
1.自己写的controller,就是我们自己写的控制器
- package com.wangbiao.springMVC;
- import javax.servlet.ServletContext;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import org.springframework.web.servlet.ModelAndView;
- import org.springframework.web.servlet.mvc.multiaction.MultiActionController;
- public class HelloWorld extends MultiActionController{
- public ModelAndView sayHelloWorld(HttpServletRequest request, HttpServletResponse response) {
- String param = request.getParameter("param");
- System.out.println("springMVC测试:helloWorld;"+param);
- ModelAndView mv = new ModelAndView();
- mv.addObject("content", "springMVC HelloWorld:"+param);
- mv.setViewName("springMVC/helloWorld");
- ServletContext ctx = this.getServletContext();
- return mv;
- }
- }
2.SpringMVC配置文件
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns="http://www.springframework.org/schema/beans"
- xmlns:mvc="http://www.springframework.org/schema/mvc"
- xmlns:context="http://www.springframework.org/schema/context"
- xmlns:aop="http://www.springframework.org/schema/aop"
- xmlns:tx="http://www.springframework.org/schema/tx"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
- http://www.springframework.org/schema/mvc
- http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
- http://www.springframework.org/schema/context
- http://www.springframework.org/schema/context/spring-context-3.0.xsd
- http://www.springframework.org/schema/aop
- http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
- http://www.springframework.org/schema/tx
- http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
- <!-- handlerMapping -->
- <bean id="beanNameUrlMapping" class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
- <bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
- <property name="mappings">
- <props>
- <prop key="/springMVC.d">/HelloWorld</prop>
- </props>
- </property>
- </bean>
- <bean name="/HelloWorld" class="com.wangbiao.springMVC.HelloWorld">
- <property name="methodNameResolver">
- <ref local="methodNameResolver"/>
- </property>
- </bean>
- <!-- 在url中对应具体的方法,通过m后面带的参数来确定方法 -->
- <bean id="methodNameResolver" class="org.springframework.web.servlet.mvc.multiaction.ParameterMethodNameResolver">
- <property name="paramName"><value>m</value></property>
- <property name="defaultMethodName"><value>execute</value></property>
- </bean>
- <!--视图解析器-->
- <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
- <!-- webroot到一指定文件夹文件路径 -->
- <property name="prefix" value="/"/>
- <!-- 视图名称后缀 -->
- <property name="suffix" value=".jsp"/>
- </bean>
- </beans>
1.DispatcherServlet注册HandlerAdapter。DispatcherServlet的initHandlerAdapters方法,红色标记的部分是关键。由于在配置文件中没有对HandlerAdapter的相关配置,所以DispatcherServlet获取到的HandlerAdapter是三个默认的HandlerAdapter对象,分别是HttpRequestHandlerAdapter,SimpleControllerHandlerAdapter和AnnotationMethodHandlerAdapter,并将这三个对象存入handlerAdapter属性中去。
- 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方法处理请求。
- protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
- HttpServletRequest processedRequest = request;
- HandlerExecutionChain mappedHandler = null;
- int interceptorIndex = -1;
- try {
- ModelAndView mv;
- boolean errorView = false;
- try {
- processedRequest = checkMultipart(request);
- // Determine handler for the current request.
- mappedHandler = getHandler(processedRequest, false);
- if (mappedHandler == null || mappedHandler.getHandler() == null) {
- noHandlerFound(processedRequest, response);
- return;
- }
- // Determine handler adapter for the current request.
- HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
- // Process last-modified header, if supported by the handler.
- String method = request.getMethod();
- boolean isGet = "GET".equals(method);
- if (isGet || "HEAD".equals(method)) {
- long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
- if (logger.isDebugEnabled()) {
- String requestUri = urlPathHelper.getRequestUri(request);
- logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified);
- }
- if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
- return;
- }
- }
- // Apply preHandle methods of registered interceptors.
- HandlerInterceptor[] interceptors = mappedHandler.getInterceptors();
- if (interceptors != null) {
- for (int i = 0; i < interceptors.length; i++) {
- HandlerInterceptor interceptor = interceptors[i];
- if (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler())) {
- triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);
- return;
- }
- interceptorIndex = i;
- }
- }
- // Actually invoke the handler.
- mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
- // Do we need view name translation?
- if (mv != null && !mv.hasView()) {
- mv.setViewName(getDefaultViewName(request));
- }
- // Apply postHandle methods of registered interceptors.
- if (interceptors != null) {
- for (int i = interceptors.length - 1; i >= 0; i--) {
- HandlerInterceptor interceptor = interceptors[i];
- interceptor.postHandle(processedRequest, response, mappedHandler.getHandler(), mv);
- }
- }
- }
- catch (ModelAndViewDefiningException ex) {
- logger.debug("ModelAndViewDefiningException encountered", ex);
- mv = ex.getModelAndView();
- }
- catch (Exception ex) {
- Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
- mv = processHandlerException(processedRequest, response, handler, ex);
- errorView = (mv != null);
- }
- // Did the handler return a view to render?
- if (mv != null && !mv.wasCleared()) {
- render(mv, processedRequest, response);
- if (errorView) {
- WebUtils.clearErrorRequestAttributes(request);
- }
- }
- else {
- if (logger.isDebugEnabled()) {
- logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
- "': assuming HandlerAdapter completed request handling");
- }
- }
- // Trigger after-completion for successful outcome.
- triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);
- }
- catch (Exception ex) {
- // Trigger after-completion for thrown exception.
- triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);
- throw ex;
- }
- catch (Error err) {
- ServletException ex = new NestedServletException("Handler processing failed", err);
- // Trigger after-completion for thrown exception.
- triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);
- throw ex;
- }
- finally {
- // Clean up any resources used by a multipart request.
- if (processedRequest != request) {
- cleanupMultipart(processedRequest);
- }
- }
- }
getHandlerAdapter方法
- protected 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?");
- }
HandlerAdapter接口
- /*
- * Copyright 2002-2008 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package org.springframework.web.servlet;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- /**
- * MVC framework SPI interface, allowing parameterization of core MVC workflow.
- *
- * <p>Interface that must be implemented for each handler type to handle a request.
- * This interface is used to allow the {@link DispatcherServlet} to be indefinitely
- * extensible. The DispatcherServlet accesses all installed handlers through this
- * interface, meaning that it does not contain code specific to any handler type.
- *
- * <p>Note that a handler can be of type <code>Object</code>. This is to enable
- * handlers from other frameworks to be integrated with this framework without
- * custom coding, as well as to allow for annotation handler objects that do
- * not obey any specific Java interface.
- *
- * <p>This interface is not intended for application developers. It is available
- * to handlers who want to develop their own web workflow.
- *
- * <p>Note: HandlerAdaptger implementators may implement the
- * {@link org.springframework.core.Ordered} interface to be able to specify a
- * sorting order (and thus a priority) for getting applied by DispatcherServlet.
- * Non-Ordered instances get treated as lowest priority.
- *
- * @author Rod Johnson
- * @author Juergen Hoeller
- * @see org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter
- * @see org.springframework.web.servlet.handler.SimpleServletHandlerAdapter
- */
- public interface HandlerAdapter {
- /**
- * Given a handler instance, return whether or not this HandlerAdapter can
- * support it. Typical HandlerAdapters will base the decision on the handler
- * type. HandlerAdapters will usually only support one handler type each.
- * <p>A typical implementation:
- * <p><code>
- * return (handler instanceof MyHandler);
- * </code>
- * @param handler handler object to check
- * @return whether or not this object can use the given handler
- */
- boolean supports(Object handler);
- /**
- * Use the given handler to handle this request.
- * The workflow that is required may vary widely.
- * @param request current HTTP request
- * @param response current HTTP response
- * @param handler handler to use. This object must have previously been passed
- * to the <code>supports</code> method of this interface, which must have
- * returned <code>true</code>.
- * @throws Exception in case of errors
- * @return ModelAndView object with the name of the view and the required
- * model data, or <code>null</code> if the request has been handled directly
- */
- ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
- /**
- * Same contract as for HttpServlet's <code>getLastModified</code> method.
- * Can simply return -1 if there's no support in the handler class.
- * @param request current HTTP request
- * @param handler handler to use
- * @return the lastModified value for the given handler
- * @see javax.servlet.http.HttpServlet#getLastModified
- * @see org.springframework.web.servlet.mvc.LastModified#getLastModified
- */
- long getLastModified(HttpServletRequest request, Object handler);
- }
来看一下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 {
- /**
- * Process the request and return a ModelAndView object which the DispatcherServlet
- * will render. A <code>null</code> return value is not an error: It indicates that
- * this object completed request processing itself, thus there is no ModelAndView
- * to render.
- * @param request current HTTP request
- * @param response current HTTP response
- * @return a ModelAndView to render, or <code>null</code> if handled directly
- * @throws Exception in case of errors
- */
- 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;
- }
- 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);
- }
- }
invokeNamedMethod方法源码
- protected final ModelAndView invokeNamedMethod(
- String methodName, HttpServletRequest request, HttpServletResponse response) throws Exception {
- 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 + "'");
- }
- 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);
- }
- //执行该方法
- 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.确定方法名后是怎么找到该方法的。
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.
- }
this.delegate其实就是继承了MultiActionController的控制对象,比如HelloWorld继承了MultiActionController,那么传过来的就是HelloWorld对象,就会将HelloWorld对象中的所有方法放到MultiActionController的handlerMethodMap属性中去了。
- 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);
- }
- }
- }
在配置文件中有这样一段代码
- <!-- 在url中对应具体的方法,通过m后面带的参数来确定方法 -->
- <bean id="methodNameResolver" class="org.springframework.web.servlet.mvc.multiaction.ParameterMethodNameResolver">
- <property name="paramName"><value>m</value></property>
- <property name="defaultMethodName"><value>execute</value></property>
- </bean>
- 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中根据方法名找方法对象。再执行这个方法就好了。
再来看看是如何从handlerMethodMap集合中找到方法并执行方法的
- 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);
- }
- }
- protected final ModelAndView invokeNamedMethod(
- String methodName, HttpServletRequest request, HttpServletResponse response) throws Exception {
- 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 + "'");
- }
- 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);
- }
- 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);
- }
- }
哎,本来是想春节之前将SpringMVC源码系列写完的,看是写不完了,还有ViewandResolve没有写,最近心境没有前一段时间平静,被外物所扰。2015年过的太平淡,感觉很重要的一年什么都没有留下,只能说很遗憾。在2016年一定要留下一些值得回味的东西,2016年不说要有多高大上,但一定要把基础打捞,框架什么的一定要很熟很熟。
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默认的适配器没有他,默认的是前面的三种。
适配处理器当然用到了适配器模式。