- 浏览: 297825 次
- 性别:
- 来自: 上海
文章分类
- 全部博客 (155)
- Liferay portal研究 (23)
- spring研究 (7)
- Displaytag (2)
- Flash Builder (0)
- 搜索引擎 (12)
- 杂项 (17)
- SCM管理 (7)
- Jquery (5)
- Linux (7)
- Oracle (10)
- httpd集成 (3)
- Maven2 (5)
- 企业管理 (1)
- tomcat高级 (4)
- dos命令 (1)
- ldap (2)
- Java (8)
- webservice (1)
- jetty代码研究 (3)
- OpenCMS (1)
- JMX (2)
- hibernate (5)
- Ant (1)
- js tree (4)
- Quartz (0)
- CMS (1)
- springside (1)
- proxool (1)
- freemarker (1)
- Cookie (1)
- CAS SSO (4)
- mysql (1)
- php (1)
- js (2)
- Asset (1)
- openmeeting (1)
- h2数据库 (2)
- wcf vs java ws (1)
最新评论
-
22199143:
...
当在重启Tomcat容器时 Exception in Thread "HouseKeeper" java.lang.NullPointerException -
liuqq:
一直用Oracle开发,几乎没有接触过其他数据库。使用Mysq ...
The Nested Set Model -
yjsxxgm:
yjsxxgm 写道FFFFFFFFFFFFFFFWWW
java 访问wcf -
yjsxxgm:
FFFFFFFFFFFFFFF
java 访问wcf -
hjp222:
scanIntervalSeconds 是重新启动,并非真正的 ...
Jetty 热部署
Spring2.5源码解读 之 基于annotation的Controller实现原理分析(1)
网上已有许多关于Spring源码解读的文章,但对于SpringMVC中基于annotation的Controller这一块,目前还没发现有相关源码解读的文章,这几天,一直在研究SpringMVC,小有所获。这里,对Spring中基于annotation的Controller的实现原理作下简单分析,作为以后学习的参考资料,如果有人也对此感兴趣,也欢迎一起研究,交流心得。
快速开始SpringMVC
1、导入核心JAR,有两种导入方式
* 导入全部JAR:spring.jar
* 导入最小JAR:spring-core、spring-beans、spring-context、spring-web、spring-webmvc
第三方依赖JAR:commons-logging.jar
2、配置核心servlet:
- <servlet>
- <servlet-name>SpringServlet</servlet-name>
- <servlet-class>
- org.springframework.web.servlet.DispatcherServlet
- </servlet-class>
- <load-on-startup>1</load-on-startup>
- </servlet>
- <servlet-mapping>
- <servlet-name>SpringServlet</servlet-name>
- <url-pattern>*.html</url-pattern>
- </servlet-mapping>
<servlet> <servlet-name>SpringServlet</servlet-name> <servlet-class> org.springframework.web.servlet.DispatcherServlet </servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>SpringServlet</servlet-name> <url-pattern>*.html</url-pattern> </servlet-mapping>
* 3、配置包扫描列表
在[servlet-name]-servlet中配置:
<context:component-scan base-package="com.spring.test" />
将所有基于annotation的handler放在test包下即可。
相当简洁的配置,体现出了的Sping的强大、灵活,不过估计不会有人这样用Spring,呵呵
源码分析之旅:
SpringMVC的核心是DispatcherServlet,网上已经有对该类的简单分析,见后面参考资料。对于handler扫描、初始化映射关系等,以后有时间再详细解读,这里只是稍微提一下:
DispatcherServlet的初始化:
- protected void initStrategies(ApplicationContext context) {
- //方法入参为ApplicationContext,可证明在DispatcherServlet初始化之前,IoC容器已经开始工作了
- initMultipartResolver(context);
- initLocaleResolver(context);
- initThemeResolver(context);
- initHandlerMappings(context);
- initHandlerAdapters(context);
- initHandlerExceptionResolvers(context);
- initRequestToViewNameTranslator(context);
- initViewResolvers(context);
- }
protected void initStrategies(ApplicationContext context) { //方法入参为ApplicationContext,可证明在DispatcherServlet初始化之前,IoC容器已经开始工作了 initMultipartResolver(context); initLocaleResolver(context); initThemeResolver(context); initHandlerMappings(context); initHandlerAdapters(context); initHandlerExceptionResolvers(context); initRequestToViewNameTranslator(context); initViewResolvers(context); }
该初始方法主要完成两件工作:
* 1、将容器中配置(在applicationContext.xml中定义)的HandlerMapping、LocaleResolver等等初始化
* 2、如果容器中未配置,则使用默认策略,该默认策略定义在DispatcherServlet.properties文件中
这其中有几个比较重要的组件(也称管道)需要初始化,包括HandlerMapping、HandlerAdapter、ViewResolver。
HandlerMapping
我们从DispatcherServlet的doService方法入手:
- protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
- ...
- //将WebApplicationContext放在了request中
- request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
- request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
- request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
- request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
- try {
- doDispatch(request, response);
- }
- ...
- }
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception { ... //将WebApplicationContext放在了request中 request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext()); request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver); request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver); request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource()); try { doDispatch(request, response); } ... }
可以看出,对于请求的处理实际上是由doDispatch()完成的,这里只对与annotation相关的部分进行分析:
- protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
- ...
- try {
- ModelAndView mv = null;
- try {
- //查找匹配的handler
- mappedHandler = getHandler(processedRequest, false);
- if (mappedHandler == null || mappedHandler.getHandler() == null) {
- //如果没有,写入404错误
- noHandlerFound(processedRequest, response);
- return;
- }
- //调用handler的方法
- HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
- mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
- ...
- }
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { ... try { ModelAndView mv = null; try { //查找匹配的handler mappedHandler = getHandler(processedRequest, false); if (mappedHandler == null || mappedHandler.getHandler() == null) { //如果没有,写入404错误 noHandlerFound(processedRequest, response); return; } //调用handler的方法 HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); ... }
再来看查找handler的过程:
- protected HandlerExecutionChain getHandler(HttpServletRequest request, boolean cache) throws Exception {
- ...
- //初始时handlerMappings中有两个:
- //1、BeanNameUrlHandlerMapping:根据bean的名字查找匹配的handler,意味我们可以在容器中将bean名以url定义,如"/order/*"
- //2、DefaultAnnotationHandlerMapping:根据annotation定义查找
- //每个handlerMapping中都维持有一个url-handler的HashMap,该列表在生成在初始化时完成
- Iterator it = this.handlerMappings.iterator();
- while (it.hasNext()) {
- HandlerMapping hm = (HandlerMapping) it.next();
- ...
- handler = hm.getHandler(request);//实际的匹配过程交由handlerMapping完成
- ...
- }
- return null;
- }
protected HandlerExecutionChain getHandler(HttpServletRequest request, boolean cache) throws Exception {
...
//初始时handlerMappings中有两个:
//1、BeanNameUrlHandlerMapping:根据bean的名字查找匹配的handler,意味我们可以在容器中将bean名以url定义,如"/order/*"
//2、DefaultAnnotationHandlerMapping:根据annotation定义查找
//每个handlerMapping中都维持有一个url-handler的HashMap,该列表在生成在初始化时完成
Iterator it = this.handlerMappings.iterator();
while (it.hasNext()) {
HandlerMapping hm = (HandlerMapping) it.next();
...
handler = hm.getHandler(request);//实际的匹配过程交由handlerMapping完成
...
}
return null;
}
实际查找handler的过程由DefaultAnnotationHandlerMapping类完成。从它的继承层次可以看出,匹配的主要工作都由其父类完成了。在父类中定义了算法的骨架,具体的处理交由子类完成,这是Templet设计模式的典型应用。[[BR]]
先看父类AbstractHandlerMapping中定义的算法骨架:
- public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
- Object handler = getHandlerInternal(request);//交由子类实现
- if (handler == null) {
- handler = getDefaultHandler();
- }
- if (handler == null) {
- return null;
- }
- if (handler instanceof String) { //如果handler是String,即完整类名,在容器中定义
- String handlerName = (String) handler;
- handler = getApplicationContext().getBean(handlerName);//从IoC中直接获取
- }
- return getHandlerExecutionChain(handler, request);
- }
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { Object handler = getHandlerInternal(request);//交由子类实现 if (handler == null) { handler = getDefaultHandler(); } if (handler == null) { return null; } if (handler instanceof String) { //如果handler是String,即完整类名,在容器中定义 String handlerName = (String) handler; handler = getApplicationContext().getBean(handlerName);//从IoC中直接获取 } return getHandlerExecutionChain(handler, request); }
AbstractHandlerMapping的子类AbstractUrlHandlerMapping中getHandlerInternal的定义:
- protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
- Object handler = lookupHandler(lookupPath, request);
- if (handler == null) {
- ...
- }
- return handler;
- }
- protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {
- // 直接匹配:
- Object handler = this.handlerMap.get(urlPath);
- if (handler != null) {
- validateHandler(handler, request);//@RequestMapping的其它属性匹配交由子类完成,如method和param的匹配
- return buildPathExposingHandler(handler, urlPath);
- }
- // 正则表达式匹配:
- String bestPathMatch = null;
- for (Iterator it = this.handlerMap.keySet().iterator(); it.hasNext();) {
- String registeredPath = (String) it.next();
- if (getPathMatcher().match(registeredPath, urlPath) &&
- (bestPathMatch == null || bestPathMatch.length() < registeredPath.length())) {
- bestPathMatch = registeredPath;//可以看出,匹配原则是按照url更长则更匹配
- }
- }
- if (bestPathMatch != null) {
- handler = this.handlerMap.get(bestPathMatch);
- validateHandler(handler, request);//@RequestMapping的其它属性匹配交由子类完成,如method和param的匹配
- String pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestPathMatch, urlPath);
- return buildPathExposingHandler(handler, pathWithinMapping);
- }
- // No handler found...
- return null;
- }
protected Object getHandlerInternal(HttpServletRequest request) throws Exception { Object handler = lookupHandler(lookupPath, request); if (handler == null) { ... } return handler; } protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception { // 直接匹配: Object handler = this.handlerMap.get(urlPath); if (handler != null) { validateHandler(handler, request);//@RequestMapping的其它属性匹配交由子类完成,如method和param的匹配 return buildPathExposingHandler(handler, urlPath); } // 正则表达式匹配: String bestPathMatch = null; for (Iterator it = this.handlerMap.keySet().iterator(); it.hasNext();) { String registeredPath = (String) it.next(); if (getPathMatcher().match(registeredPath, urlPath) && (bestPathMatch == null || bestPathMatch.length() < registeredPath.length())) { bestPathMatch = registeredPath;//可以看出,匹配原则是按照url更长则更匹配 } } if (bestPathMatch != null) { handler = this.handlerMap.get(bestPathMatch); validateHandler(handler, request);//@RequestMapping的其它属性匹配交由子类完成,如method和param的匹配 String pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestPathMatch, urlPath); return buildPathExposingHandler(handler, pathWithinMapping); } // No handler found... return null; }
子类DefaultAnnotationHandlerMapping中@RequestMapping的匹配过程:
- protected void validateHandler(Object handler, HttpServletRequest request) throws Exception {
- RequestMapping mapping = this.cachedMappings.get(handler.getClass());
- if (mapping == null) {
- mapping = AnnotationUtils.findAnnotation(handler.getClass(), RequestMapping.class);
- }
- if (mapping != null) {
- validateMapping(mapping, request);//具体的匹配在validateMapping中完成
- }
- }
- protected void validateMapping(RequestMapping mapping, HttpServletRequest request) throws Exception {
- RequestMethod[] mappedMethods = mapping.method();
- //请求方法是否匹配?
- if (!ServletAnnotationMappingUtils.checkRequestMethod(mappedMethods, request)) {
- String[] supportedMethods = new String[mappedMethods.length];
- for (int i = 0; i < mappedMethods.length; i++) {
- supportedMethods[i] = mappedMethods[i].name();
- }
- throw new HttpRequestMethodNotSupportedException(request.getMethod(), supportedMethods);//直接就抛异常了?似乎不妥,为什么不尝试下一个比较匹配的那个URL呢?也有可能是父类的算法定义有问题
- }
- //请求参数是否匹配?
- String[] mappedParams = mapping.params();
- if (!ServletAnnotationMappingUtils.checkParameters(mappedParams, request)) {
- throw new ServletException("Parameter conditions {" +
- StringUtils.arrayToDelimitedString(mappedParams, ", ") +
- "} not met for request parameters: " + request.getParameterMap());
- }
- }
protected void validateHandler(Object handler, HttpServletRequest request) throws Exception { RequestMapping mapping = this.cachedMappings.get(handler.getClass()); if (mapping == null) { mapping = AnnotationUtils.findAnnotation(handler.getClass(), RequestMapping.class); } if (mapping != null) { validateMapping(mapping, request);//具体的匹配在validateMapping中完成 } } protected void validateMapping(RequestMapping mapping, HttpServletRequest request) throws Exception { RequestMethod[] mappedMethods = mapping.method(); //请求方法是否匹配? if (!ServletAnnotationMappingUtils.checkRequestMethod(mappedMethods, request)) { String[] supportedMethods = new String[mappedMethods.length]; for (int i = 0; i < mappedMethods.length; i++) { supportedMethods[i] = mappedMethods[i].name(); } throw new HttpRequestMethodNotSupportedException(request.getMethod(), supportedMethods);//直接就抛异常了?似乎不妥,为什么不尝试下一个比较匹配的那个URL呢?也有可能是父类的算法定义有问题 } //请求参数是否匹配? String[] mappedParams = mapping.params(); if (!ServletAnnotationMappingUtils.checkParameters(mappedParams, request)) { throw new ServletException("Parameter conditions {" + StringUtils.arrayToDelimitedString(mappedParams, ", ") + "} not met for request parameters: " + request.getParameterMap()); } }
请求方法及参数的匹配过程由ServletAnnotationMappingUtils类的静态方法完成,逻辑比较简单:
- public static boolean checkRequestMethod(RequestMethod[] methods, HttpServletRequest request) {
- if (!ObjectUtils.isEmpty(methods)) {
- boolean match = false;
- for (RequestMethod method : methods) {
- if (method.name().equals(request.getMethod())) {
- match = true;
- }
- }
- if (!match) {
- return false;
- }
- }
- return true;
- }
- public static boolean checkParameters(String[] params, HttpServletRequest request) {
- if (!ObjectUtils.isEmpty(params)) {
- for (String param : params) {
- int separator = param.indexOf('=');
- if (separator == -1) {
- if (param.startsWith("!")) {
- if (WebUtils.hasSubmitParameter(request, param.substring(1))) {
- return false;
- }
- }
- else if (!WebUtils.hasSubmitParameter(request, param)) {
- return false;
- }
- }
- else {
- String key = param.substring(0, separator);
- String value = param.substring(separator + 1);
- if (!value.equals(request.getParameter(key))) {
- return false;
- }
- }
- }
- }
- return true;
- }
public static boolean checkRequestMethod(RequestMethod[] methods, HttpServletRequest request) { if (!ObjectUtils.isEmpty(methods)) { boolean match = false; for (RequestMethod method : methods) { if (method.name().equals(request.getMethod())) { match = true; } } if (!match) { return false; } } return true; } public static boolean checkParameters(String[] params, HttpServletRequest request) { if (!ObjectUtils.isEmpty(params)) { for (String param : params) { int separator = param.indexOf('='); if (separator == -1) { if (param.startsWith("!")) { if (WebUtils.hasSubmitParameter(request, param.substring(1))) { return false; } } else if (!WebUtils.hasSubmitParameter(request, param)) { return false; } } else { String key = param.substring(0, separator); String value = param.substring(separator + 1); if (!value.equals(request.getParameter(key))) { return false; } } } } return true; }
至此,handler的匹配过程结束,bean的实例作为匹配的handler返回。可以看出,匹配过程并未深入到方法一级,如果类级别和方法级别都定义了url,在这一层次会忽略方法级别的。其实,spring也不推荐在类级别和方法级别同时定义url。[[BR]]
再回到DispatcherServlet中,找到匹配handler后,下一步就要去调用handler,调用的方式有许多,spring抽像出了一个接口HandlerAdapter,接口的定义:
- public interface HandlerAdapter {
- boolean supports(Object handler); //是否支持此种类型的handler
- ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception; //具体的处理过程
- long getLastModified(HttpServletRequest request, Object handler);
- }
public interface HandlerAdapter { boolean supports(Object handler); //是否支持此种类型的handler ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception; //具体的处理过程 long getLastModified(HttpServletRequest request, Object handler); }
DispatcherServlet中寻找合适的HandlerAdapter的过程:
- protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
- /*
- spring默认提供四个HandlerAdapter:
- HttpRequestHandlerAdapter:处理HttpRequestHandler接口的实例
- SimpleControllerHandlerAdapter:处理Controller接口的实例
- ThrowawayControllerHandlerAdapter:已经过时
- AnnotationMethodHandlerAdapter:处理annotation定义的实例
- */
- Iterator it = this.handlerAdapters.iterator();
- while (it.hasNext()) {
- HandlerAdapter ha = (HandlerAdapter) it.next();
- if (logger.isDebugEnabled()) {
- logger.debug("Testing handler adapter [" + ha + "]");
- }
- if (ha.supports(handler)) {
- return ha;
- }
- }
- ...
- }
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException { /* spring默认提供四个HandlerAdapter: HttpRequestHandlerAdapter:处理HttpRequestHandler接口的实例 SimpleControllerHandlerAdapter:处理Controller接口的实例 ThrowawayControllerHandlerAdapter:已经过时 AnnotationMethodHandlerAdapter:处理annotation定义的实例 */ Iterator it = this.handlerAdapters.iterator(); while (it.hasNext()) { HandlerAdapter ha = (HandlerAdapter) it.next(); if (logger.isDebugEnabled()) { logger.debug("Testing handler adapter [" + ha + "]"); } if (ha.supports(handler)) { return ha; } } ... }
基于annotation的handler则是由AnnotationMethodHandlerAdapter进行处理,来看AnnotationMethodHandlerAdapter中相关处理代码:
- //是否支持此类型的handler?
- public boolean supports(Object handler) {
- return getMethodResolver(handler).hasHandlerMethods();
- }
- private ServletHandlerMethodResolver getMethodResolver(Object handler) {
- Class handlerClass = ClassUtils.getUserClass(handler);
- ServletHandlerMethodResolver resolver = this.methodResolverCache.get(handlerClass);
- if (resolver == null) {
- resolver = new ServletHandlerMethodResolver(handlerClass);//在父类的构造方法中完成handler的解析
- this.methodResolverCache.put(handlerClass, resolver);//缓存起来,方法调用时有用
- }
- return resolver;
- }
- public final boolean hasHandlerMethods() {
- return !this.handlerMethods.isEmpty();//非常简单的判断,如果该类中的方法标记有@RequestMapping就返回true,也意味着它支持此种类型的handler
- }
//是否支持此类型的handler? public boolean supports(Object handler) { return getMethodResolver(handler).hasHandlerMethods(); } private ServletHandlerMethodResolver getMethodResolver(Object handler) { Class handlerClass = ClassUtils.getUserClass(handler); ServletHandlerMethodResolver resolver = this.methodResolverCache.get(handlerClass); if (resolver == null) { resolver = new ServletHandlerMethodResolver(handlerClass);//在父类的构造方法中完成handler的解析 this.methodResolverCache.put(handlerClass, resolver);//缓存起来,方法调用时有用 } return resolver; } public final boolean hasHandlerMethods() { return !this.handlerMethods.isEmpty();//非常简单的判断,如果该类中的方法标记有@RequestMapping就返回true,也意味着它支持此种类型的handler }
好了,到这里,handler已确定,由谁去处理handler也已确定,剩下的工作就是如何调用了。来看具体的调用代码:
- public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
- throws Exception {
- ...
- if (this.synchronizeOnSession) {
- HttpSession session = request.getSession(false);
- if (session != null) {
- Object mutex = WebUtils.getSessionMutex(session);
- synchronized (mutex) {
- return invokeHandlerMethod(request, response, handler);
- }
- }
- }
- return invokeHandlerMethod(request, response, handler);
- }
- protected ModelAndView invokeHandlerMethod(
- HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
- try {
- ServletHandlerMethodResolver methodResolver = getMethodResolver(handler);//缓存中已有
- Method handlerMethod = methodResolver.resolveHandlerMethod(request);//确定具体该调用哪个方法
- ServletHandlerMethodInvoker methodInvoker = new ServletHandlerMethodInvoker(methodResolver);
- ServletWebRequest webRequest = new ServletWebRequest(request, response);
- ExtendedModelMap implicitModel = new ExtendedModelMap();//方法入参ModelMap的原型
- Object result = methodInvoker.invokeHandlerMethod(handlerMethod, handler, webRequest, implicitModel);//调用方法
- ModelAndView mav =
- methodInvoker.getModelAndView(handlerMethod, handler.getClass(), result, implicitModel, webRequest);//构建ModelAndView
- methodInvoker.updateModelAttributes(
- handler, (mav != null ? mav.getModel() : null), implicitModel, webRequest);//处理ModelMap中的值
- return mav;
- }
- catch (NoSuchRequestHandlingMethodException ex) {
- return handleNoSuchRequestHandlingMethod(ex, request, response);
- }
- }
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { ... if (this.synchronizeOnSession) { HttpSession session = request.getSession(false); if (session != null) { Object mutex = WebUtils.getSessionMutex(session); synchronized (mutex) { return invokeHandlerMethod(request, response, handler); } } } return invokeHandlerMethod(request, response, handler); } protected ModelAndView invokeHandlerMethod( HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { try { ServletHandlerMethodResolver methodResolver = getMethodResolver(handler);//缓存中已有 Method handlerMethod = methodResolver.resolveHandlerMethod(request);//确定具体该调用哪个方法 ServletHandlerMethodInvoker methodInvoker = new ServletHandlerMethodInvoker(methodResolver); ServletWebRequest webRequest = new ServletWebRequest(request, response); ExtendedModelMap implicitModel = new ExtendedModelMap();//方法入参ModelMap的原型 Object result = methodInvoker.invokeHandlerMethod(handlerMethod, handler, webRequest, implicitModel);//调用方法 ModelAndView mav = methodInvoker.getModelAndView(handlerMethod, handler.getClass(), result, implicitModel, webRequest);//构建ModelAndView methodInvoker.updateModelAttributes( handler, (mav != null ? mav.getModel() : null), implicitModel, webRequest);//处理ModelMap中的值 return mav; } catch (NoSuchRequestHandlingMethodException ex) { return handleNoSuchRequestHandlingMethod(ex, request, response); } }
其中,确定具体调用哪个方法这个过程比较复杂,由ServletHandlerMethodResolver完成。
- public Method resolveHandlerMethod(HttpServletRequest request) throws ServletException {
- ...
- for (Method handlerMethod : getHandlerMethods()) {
- RequestMappingInfo mappingInfo = new RequestMappingInfo();
- RequestMapping mapping = AnnotationUtils.findAnnotation(handlerMethod, RequestMapping.class);
- mappingInfo.paths = mapping.value();
- //如果类级别没有定义@RequestMapping,则使用方法级别定义的
- if (!hasTypeLevelMapping() || !Arrays.equals(mapping.method(), getTypeLevelMapping().method())) {
- mappingInfo.methods = mapping.method();
- }
- if (!hasTypeLevelMapping() || !Arrays.equals(mapping.params(), getTypeLevelMapping().params())) {
- mappingInfo.params = mapping.params();
- }
- boolean match = false;
- if (mappingInfo.paths.length > 0) {//先检查url是否匹配
- for (String mappedPath : mappingInfo.paths) {
- if (isPathMatch(mappedPath, lookupPath)) {
- if (checkParameters(mappingInfo, request)) {
- match = true;
- targetPathMatches.put(mappingInfo, mappedPath);
- }
- else {
- break;
- }
- }
- }
- }
- else {
-
//如果没有定义url,则只需检查其它项是否匹配,如param、method
发表评论
-
spring 注释
2010-04-08 22:09 1213Spring框架从创建伊始就 ... -
spring 注释通俗简介
2010-01-04 16:09 1210在一个稍大的项目中,通常会有上百个组件,如果这些组件采用xml ... -
sring 多数据源
2009-12-02 13:14 2037Spring2.0.1以后的版本已经支持配置多数据源,并且可以 ... -
resetful spring
2009-11-24 14:57 1024http://badqiu.iteye.com/blog/47 ... -
spring side3 学习地址的
2009-10-23 10:19 814spring side3 学习地址的:http://www.b ... -
ssh最简单配置文件
2008-12-12 10:31 939<bean id="sessionFact ...
相关推荐
三相LCL并网逆变器:高精度快速响应的有功无功解耦控制技术,三相LCL并网逆变器,有功无功解耦控制,控制精度高,响应速度快。 ,三相LCL并网逆变器; 有功无功解耦控制; 高控制精度; 快速响应。,三相LCL逆变器高精度快速响应解耦控制
一种基于Lifelogging视频的文本标签生成模型.pdf
基于黏菌优化算法(SMA)的改进与复现——融合EO算法更新策略的ESMA项目报告,黏菌优化算法(SMA)复现(融合EO算法改进更新策略)——ESMA。 复现内容包括:改进算法实现、23个基准测试函数、多次实验运行并计算均值标准差等统计量、与SMA对比等。 程序基本上每一步都有注释,非常易懂,代码质量极高,便于新手学习和理解。 ,SMA复现;EO算法改进;算法实现;基准测试函数;实验运行;统计量;SMA对比;程序注释;代码质量;学习理解。,标题:ESMA算法复现:黏菌优化与EO算法融合改进的实证研究
免费JAVA毕业设计 2024成品源码+论文+数据库+启动教程 启动教程:https://www.bilibili.com/video/BV1SzbFe7EGZ 项目讲解视频:https://www.bilibili.com/video/BV1Tb421n72S 二次开发教程:https://www.bilibili.com/video/BV18i421i7Dx
基于数据挖掘的教师教育质量评价指标体系的构建.pdf
内容概要:本实验报告旨在介绍将正则表达式(RE)转化为非确定有限自动机(NFA)的过程与技术细节。内容包括了理论背景的介绍,比如为什么需要这样的转换以及它背后的数学逻辑;详细解释如何通过编写特定功能的程序完成从正则表达式到NFA的状态迁移图构建;并且探讨了后续将这个NFA再转变成DFA(确定有限自动机)并进行优化的方法。最后,通过一组具体的例子来进行验证性的实践操作,并讨论在整个过程中遇到的各种挑战及解决方案。此外,报告还包含了对于不同设计方案的选择考量,以及对于所选技术和工具的应用评估。 适用人群:对于希望深入理解编译原理、特别是形式语言和自动机构造的学生或专业人士来说是一份宝贵的学习资料。 使用场景及目标:本篇文章主要用于教育指导,适用于大学本科计算机科学专业相关课程的教学辅助材料,帮助学生更好地理解复杂概念之间的联系。通过动手实践可以强化他们对该领域关键知识点的记忆和技术能力。 其他说明:文中提供的源代码实例和图表有助于使用者更直观地领会转换过程的具体步骤,同时也有助于培养解决问题的能力和思维方式。
nodejs010-1.2-29.el6.centos.alt.x86_64.rpm
"基于萤火虫算法优化麻雀算法的深度置信网络FSSSA-DBN数据分类预测模型及其Matlab代码详解",基于萤火虫算法改进麻雀算法优化深度置信网络(FSSSA-DBN)的数据分类预测 matlab代码注释详细, ,核心关键词:基于萤火虫算法; 改进麻雀算法; 优化深度置信网络(FSSSA-DBN); 数据分类预测; MATLAB代码注释详细。,基于FSSSA-DBN的深度分类预测算法的MATLAB代码注释
基于自适应粒子群算法的源储容量配置优化策略:考虑合作博弈与Shapley分配模型的研究报告,考虑合作博弈的源储容量配置代码 采用自适应粒子群算法编写 考虑shapley分配模型对收益进行分配 容量配置+优化调度 本人亲自编写,附参考文献,可改写性强,可。 ,合作博弈; 自适应粒子群算法; 容量配置优化调度; 收益分配模型(Shapley); 参考注释。,基于Shapley分配的容量配置优化与调度代码:自适应粒子群算法的实现
nodejs010-nodejs-editor-0.0.5-1.el6.centos.alt.noarch.rpm
免费JAVA毕业设计 2024成品源码+论文+录屏+启动教程 启动教程:https://www.bilibili.com/video/BV1SzbFe7EGZ 项目讲解视频:https://www.bilibili.com/video/BV1Tb421n72S 二次开发教程:https://www.bilibili.com/video/BV18i421i7Dx
《深入解析与复现:基于ICMIC混沌初始化的SHSSA算法及其与SSA的对比研究》,麻雀搜索算法(SSA)复现:《螺旋探索与自适应混合变异的麻雀搜索算法_陈功》 策略为:ICMIC混沌初始化种群+螺旋探索改进发现者策略+精英差分扰动策略+随机反向扰动策略——SHSSA 复现内容包括:改进SSA算法实现、23个基准测试函数、改进策略因子画图分析、相关混沌图分析、与SSA对比等。 程序基本上每一步都有注释,非常易懂,代码质量极高,便于新手学习和理解。 ,麻雀搜索算法(SSA)复现; 螺旋探索; 自适应混合变异; ICMIC混沌初始化种群; 策略因子画图分析; 代码质量高; 对比实验。,麻雀搜索算法(SSA)的SHSSA策略复现与对比分析
免费JAVA毕业设计 2024成品源码+论文+数据库+启动教程 启动教程:https://www.bilibili.com/video/BV1SzbFe7EGZ 项目讲解视频:https://www.bilibili.com/video/BV1Tb421n72S 二次开发教程:https://www.bilibili.com/video/BV18i421i7Dx
基于MATLAB/SIMULINK仿真的永磁同步电动机双闭环控制系统研究:变频侧五电平控制与整流侧三电平控制的实现与优化(默认MATLAB 2018b环境),MATLAB,SIMULINK仿真 永磁同步电动机,转速电流双闭环 变频侧五电平控制,整流侧三电平控制 默认MATLAB2018b ,MATLAB; SIMULINK仿真; 永磁同步电动机; 转速电流双闭环; 五电平控制; 三电平控制; MATLAB2018b,MATLAB中永磁同步电机双闭环五电平控制策略研究
《利用HFSS软件自制的角锥(矩形)喇叭天线模型:结果展示与参数化调整教程》,HFSS角锥(矩形)喇叭天线 天线模型,附带结果,可改参数,HFSS软件包 自己做的,保证正确(有教程,具体到每一步,可以自己做出来参考bao gao) ,HFSS; 角锥喇叭天线; 矩形; 天线模型; 附带结果; 可改参数; HFSS软件包; 自制; 保证正确; 教程,HFSS软件角锥喇叭天线模型:可改参数保证正确结果
1、文件内容:publican-redhat-2.7-6.el7.rpm以及相关依赖 2、文件形式:tar.gz压缩包 3、安装指令: #Step1、解压 tar -zxvf /mnt/data/output/publican-redhat-2.7-6.el7.tar.gz #Step2、进入解压后的目录,执行安装 sudo rpm -ivh *.rpm 4、安装指导:私信博主,全程指导安装
,java多用户商城源码,多用户b2b2c商城源码,商城小程序源码,java小程序源码 PC+H5+小程序+APP源码,多用户商城APP源码, 开发语言:java+springboot+vue+uniapp
"MATLAB Simulink驱动下的光储微电网并网系统优化:改进光伏MPPT控制,实现蓄电池SOC均衡控制策略重构,拓展可增加蓄电池组的应用",MATLAB Simulink#改进光储微电网并网系统 光伏MPPT控制 蓄电池SOC均衡控制策略 重构,可增加蓄电池组 ,MATLAB Simulink; 改进光储微电网并网系统; 光伏MPPT控制; 蓄电池SOC均衡控制策略; 蓄电池组重构,"MATLAB Simulink下的光储微电网并网系统优化研究"
nodejs010-nodejs-ctype-0.5.3-3.1.el6.centos.alt.noarch.rpm
免费JAVA毕业设计 2024成品源码+论文+数据库+启动教程 启动教程:https://www.bilibili.com/video/BV1SzbFe7EGZ 项目讲解视频:https://www.bilibili.com/video/BV1Tb421n72S 二次开发教程:https://www.bilibili.com/video/BV18i421i7Dx