SpringMVC之 HandlerAdapter和handlerMapping
HandlerAdapter字面上的意思就是处理适配器,它的作用用一句话概括就是调用具体的方法对用户发来的请求来进行处理。当handlerMapping获取到执行请求的controller时,DispatcherServlte会根据controller对应的controller类型来调用相应的HandlerAdapter来进行处理。
在贴源码之前先说一下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;
- }
- }
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>
<?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");
- }
- }
- }
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);
- }
- }
- }
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?");
- }
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);
- }
/*
* 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); }
再来看一下自己写的控制器HelloWorld继承了MultiActionController。MultiActionController又继承了AbstractController,AbstractController实现了Controller。这样就看DispatcherServlet属性中的HandlerApater谁支持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;
- }
- }
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;
- }
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;
- }
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);
- }
- }
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 {
- 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);
- }
- }
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.
- }
public MultiActionController() {
this.delegate = this;
registerHandlerMethods(this.delegate);
// We'll accept no handler methods found here - a delegate might be set later on.
}
registerHandlerMethods方法
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);
- }
- }
- }
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>
<!-- 在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>
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;
- }
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 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);
- }
- }
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);
}
}
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默认的适配器没有他,默认的是前面的三种。
SpringMVC之 HandlerAdapter和handlerMapping的更多相关文章
- springMVC源码分析--HandlerMapping(一)
HandlerMapping的工作就是为每个请求找到合适的请求找到一个处理器handler,其实现机制简单来说就是维持了一个url到Controller关系的Map结构,其提供的实际功能也是根据req ...
- SpringMVC源码解读 - HandlerMapping
SpringMVC在请求到handler处理器的分发这步是通过HandlerMapping模块解决的.handlerMapping 还处理拦截器. 先看看HandlerMapping的继承树吧 可以大 ...
- SpringMVC之HandlerAdapter解析
HandlerAdapter字面上的意思就是处理适配器,它的作用用一句话概括就是调用具体的方法对用户发来的请求来进行处理.当handlerMapping获取到执行请求的controller时,Disp ...
- SpringMVC笔记- 不配置HandlerMapping
使用SpringMVC框架时发现有的配置了HandlerMapping,而有的没有,那么它们有什么区别呢?不配置能不能正常使用框架呢? 下面我们看一看不配置任何HandlerMapping时,框架会使 ...
- springmvc源码笔记-HandlerMapping注入
在springmvc中,如何根据url找到controller以及对应方法,依赖的是HandlerMapping接口的getHandler方法 在spring容器中默认注册的HandlerMappin ...
- 01基于配置文件方式的SpringMVC,三种HandlerMapping,三种控制器
1 添加Spring MVC所需的jar包. 2 创建一个以下项目结构的springmvc项目 3 web.xml的配置如下: <?xmlversion="1.0"en ...
- SpringMVC源码解读 - HandlerMapping - RequestMappingHandlerMapping请求分发
AbstractHandlerMethodMapping实现接口getHandlerInternal,定义查找流程 RequestMappingInfoHandlerMapping根据RequestM ...
- SpringMVC源码解读 - HandlerMapping - AbstractUrlHandlerMapping系列request分发
AbstractHandlerMapping实现HandlerMapping接口定的getHandler 1. 提供getHandlerInternal模板方法给子类实现 2. 如果没有获取Handl ...
- SpringMVC源码解读 - HandlerMapping - SimpleUrlHandlerMapping初始化
摘要: SimpleUrlHandlerMapping只是参与Handler的注册,请求映射时由AbstractUrlHandlerMapping搞定. 初始化时,通过setMappings(Prop ...
随机推荐
- 为什要使用预编译SQL?
今天在研发部技术大牛的指点下,我终于明白了为什么要使用SQL预编译的形式执行数据库JDBC:
- C# 获取QQ好友列表信息的实现
分析部分 当我们访问QQ空间的时候,大家可以在右侧的发现一个这样的统计信息 当点击这个链接的时候,会跳转到 这样一个URL 这个URl可以管理好友,当然也就能读取到好友 上面我们是在浏览器中的操 ...
- bzoj2957楼房重建——线段树
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2957 线段树维护原点到楼顶的斜率,可以知道答案就是从原点开始斜率递增的个数: 记录一个mx数 ...
- 获取当前正在运行的activity
adb shell dumpsys activity activities | findstr "Run"
- EasyUI 下载与引用
1.官网下载地址: http://www.jeasyui.com/download/index.php 一般下载 “GPL Edition” (开源版本). 2.目录结构: demo:案例,可以删 l ...
- Servlet中init-param与context-param的区别
web.xml文件中Servlet中配置如下: <servlet> <servlet-name>loginServlet</servlet-name> <se ...
- Asset Catalog Help (四)---Adding an iOS App Icon Set or Launch Image Set
Adding an iOS App Icon Set or Launch Image Set Organize different resolutions of your app icons and ...
- 【eclipse插件开发实战】 Eclipse插件开发6——eclipse在线翻译插件Translator开发实例详解
Eclipse插件开发6--eclipse在线翻译插件Translator开发实例详解 在上一篇文章中讲到了一个简单的eclipse插件开发实例,主要是对插件工程的基本创建步骤进行了讲解,这篇文章当中 ...
- ASP.NET Core会议管理平台实战_1、开篇介绍
用到四个数据库
- tableView刷新指定的cell 或section和滚动到指定的位置
转自:http://blog.csdn.net/tianyou_code/article/details/54426494 //一个section刷新 NSIndexSet *indexSet=[[N ...