spring mvc问题之为何多注入了一个BeanNameUrlHandlerMapping?
2017-09-04 15:44
465 查看
最近在研究springmvc,为了把各种配置方式都了解一下,所以在springmvc的配置文件里组合了几种算是常用的handlermapping和controller组件的配置方式,包括注解配置方式以及xml配置方式,配置文件如下:
然后从spring官网下载了springmvc的源码,看了一下DispatcherServlet类的启动加载过程,在debug的过程中发现一个问题。
在DispatcherServlet初始化完handlerMappings后,watch发现里面的内容为:
[org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping@52f7b4, org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping@1046021, org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping@432d9d, org.springframework.web.servlet.handler.SimpleUrlHandlerMapping@67dd20]
在spring-mvc.xml中,我明明只配置了一个BeanNameUrlHandlerMapping,但是handlerMappings里怎么会有两个?
然后我把spring-mvc.xml中配置的BeanNameUrlHandlerMapping注释掉,再去debug,handlerMappings里的内容变为:
[org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping@560c4c, org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping@1418e46, org.springframework.web.servlet.handler.SimpleUrlHandlerMapping@e39b6f]
BeanNameUrlHandlerMapping对象只剩下了一个,那剩下的那个是哪儿来的呢?
看了一下watch里面两个对象的信息,复制到比较工具中,只有order有明显区别
继续去网上搜了一下,发现有个帖子跟我的疑问比较类似
原帖地址:http://www.cnblogs.com/beiyeren/p/3488170.html
原文如下:
找到MvcNamespaceUtils的源码,debug发现是在DefaultListableBeanFactory中的beanDefinitionMap里查找bean名称为org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping的Bean定义映射关系
既然此处回去查找bean名称为org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping的Bean定义映射关系,那后面我猜想应该会根据这个映射关系去创建name为org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping的bean对象,也就是多出来的那个BeanNameUrlHandlerMapping对象,如果是这样的话,那我把自己配置的那个BeanNameUrlHandlerMapping类型的bean的name设置成org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,最后是不是就会覆盖系统自动生成的BeanNameUrlHandlerMapping对象?
经试验,不管是设置了id还是name为org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,handlermapping中最后只有一个BeanNameUrlHandlerMapping对象:
[org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping@3bc849, org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping@da33d1, org.springframework.web.servlet.handler.SimpleUrlHandlerMapping@17ffe93]
[org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping@c3dbbc, org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping@8f529b, org.springframework.web.servlet.handler.SimpleUrlHandlerMapping@178676e]
但是,如果这样设置的话,应该相当于是用我设置的对象去覆盖了系统设置的对象,还是会多了生成系统自动设置的SimpleUrlHandlerMapping对象这一步,并且在MvcNamespaceUtils类的registerBeanNameUrlHandlerMapping方法中debug,确实DefaultListableBeanFactory中的beanDefinitionMap里没有bean名称为org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping的Bean定义映射关系,应该也就证实了我的猜想。那有没有办法彻底让系统不去生成默认的SimpleUrlHandlerMapping对象呢?
我又Watch了一下beanDefinitionMap里包含的数据:
{
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#0=Root bean: class [org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null,
org.springframework.web.servlet.handler.MappedInterceptor#0=Root bean: class [org.springframework.web.servlet.handler.MappedInterceptor]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null,
org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver#0=Root bean: class [org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null,
mvcContentNegotiationManager=Root bean: class [org.springframework.web.accept.ContentNegotiationManagerFactoryBean]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null,
org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver#0=Root bean: class [org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null,
org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver#0=Root bean: class [org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null,
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#0=Root bean: class [org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null,
org.springframework.format.support.FormattingConversionServiceFactoryBean#0=Root bean: class [org.springframework.format.support.FormattingConversionServiceFactoryBean]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null
}
然后在springmvc的源码中搜索了其中两个beanname
发现都是在org.springframework.web.servlet.config.AnnotationDrivenBeanDefinitionParser这个类中加入到context里的,看这个类应该是跟注解相关的解析类。所以我猜想是不是因为开启了注解驱动的Spring MVC组件模式的原因?
注释掉
其实从MvcNamespaceUtils类的registerBeanNameUrlHandlerMapping方法调用栈也可以看出来,跟AnnotationDrivenBeanDefinitionParser这个类是有关系的:
然后我又试了保留
说明系统开启了注解驱动的Spring MVC组件模式情况下生成的默认的BeanNameUrlHandlerMapping对象,用于处理Web请求与xml配置的具体请求处理控制器之间的映射匹配,是个中间人角色,也会作为Web请求和注解配置的controller组件的中间人。至于为什么会在这种情况下生成默认的BeanNameUrlHandlerMapping对象,我觉得应该是为了在使用注解配置的BeanName类型的controller时,不需要再关心HandlerMapping的问题,毕竟BeanNameUrlHandlerMapping是个底层对象,不需要再对其进行继承重写或者组合到其他对象中,那就启动的时候默认生成一个就好了。
所以如果开启了注解驱动的Spring MVC组件模式,就不需要手动在xml中配置BeanNameUrlHandlerMapping。
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd"> <!-- 开启后仍需结合<context:component-scan>使用 --> <mvc:annotation-driven /> <!-- 使用XML来启用组件扫描 --> <!-- <context:component-scan/>会到指定的包(package)下面扫描标注有@Component的类,所以Controller要被扫描到,一定要加上@Component注解 --> <!-- 扫描controller(controller层注入) --> <!-- 如果需要被springmvc识别为controller组件,需要结合<mvc:annotation-driven>使用 --> <context:component-scan base-package="com.invest.controller" /> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"> </bean> <bean name="/hello" class="com.invest.controller.HelloWorldController"/> <!-- 可以不加id和name --> <bean id="handlerMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> <property name="mappings"> <props> <prop key="index.do">investorController2</prop> <prop key="3333.do">investorController3</prop> </props> </property> </bean> <bean name="investorController2" class="com.invest.controller.InvestorController2"/> <!-- 对模型视图添加前后缀 --> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver" p:prefix="/WEB-INF/view/" p:suffix=".jsp" /> </beans>
然后从spring官网下载了springmvc的源码,看了一下DispatcherServlet类的启动加载过程,在debug的过程中发现一个问题。
在DispatcherServlet初始化完handlerMappings后,watch发现里面的内容为:
[org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping@52f7b4, org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping@1046021, org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping@432d9d, org.springframework.web.servlet.handler.SimpleUrlHandlerMapping@67dd20]
在spring-mvc.xml中,我明明只配置了一个BeanNameUrlHandlerMapping,但是handlerMappings里怎么会有两个?
然后我把spring-mvc.xml中配置的BeanNameUrlHandlerMapping注释掉,再去debug,handlerMappings里的内容变为:
[org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping@560c4c, org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping@1418e46, org.springframework.web.servlet.handler.SimpleUrlHandlerMapping@e39b6f]
BeanNameUrlHandlerMapping对象只剩下了一个,那剩下的那个是哪儿来的呢?
看了一下watch里面两个对象的信息,复制到比较工具中,只有order有明显区别
继续去网上搜了一下,发现有个帖子跟我的疑问比较类似
原帖地址:http://www.cnblogs.com/beiyeren/p/3488170.html
原文如下:
最近在调试项目时,debug DispatcherServlet时,发现handlerMappings属性包含了RequestMappingHandlerMapping、SimpleUrlHandlerMapping、BeanNameUrlHandlerMapping。 可是我明明只声明了 <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"></bean> 真是百思不得解啊,因为是旧项目基础改造的,以为是别的地方有隐秘用法,找了半天,没找到,今天下班时,突然想到我注册了 <mvc:resources location="" mapping=""/> 翻看ResourcesBeanDefinitionParser,查到了关键代码: 1. RootBeanDefinition handlerMappingDef = new RootBeanDefinition(SimpleUrlHandlerMapping.class); handlerMappingDef.setSource(source); handlerMappingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); handlerMappingDef.getPropertyValues().add("urlMap", urlMap); 2. // Ensure BeanNameUrlHandlerMapping (SPR-8289) and default HandlerAdapters are not "turned off" // Register HttpRequestHandlerAdapter MvcNamespaceUtils.registerDefaultComponents(parserContext, source); 指向 public static void registerDefaultComponents(ParserContext parserContext, Object source) { registerBeanNameUrlHandlerMapping(parserContext, source); registerHttpRequestHandlerAdapter(parserContext, source); registerSimpleControllerHandlerAdapter(parserContext, source); } 才知道原因了。呵呵。
找到MvcNamespaceUtils的源码,debug发现是在DefaultListableBeanFactory中的beanDefinitionMap里查找bean名称为org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping的Bean定义映射关系
既然此处回去查找bean名称为org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping的Bean定义映射关系,那后面我猜想应该会根据这个映射关系去创建name为org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping的bean对象,也就是多出来的那个BeanNameUrlHandlerMapping对象,如果是这样的话,那我把自己配置的那个BeanNameUrlHandlerMapping类型的bean的name设置成org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,最后是不是就会覆盖系统自动生成的BeanNameUrlHandlerMapping对象?
经试验,不管是设置了id还是name为org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,handlermapping中最后只有一个BeanNameUrlHandlerMapping对象:
<bean name="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"> </bean>
[org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping@3bc849, org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping@da33d1, org.springframework.web.servlet.handler.SimpleUrlHandlerMapping@17ffe93]
<bean id="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"> </bean>
[org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping@c3dbbc, org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping@8f529b, org.springframework.web.servlet.handler.SimpleUrlHandlerMapping@178676e]
但是,如果这样设置的话,应该相当于是用我设置的对象去覆盖了系统设置的对象,还是会多了生成系统自动设置的SimpleUrlHandlerMapping对象这一步,并且在MvcNamespaceUtils类的registerBeanNameUrlHandlerMapping方法中debug,确实DefaultListableBeanFactory中的beanDefinitionMap里没有bean名称为org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping的Bean定义映射关系,应该也就证实了我的猜想。那有没有办法彻底让系统不去生成默认的SimpleUrlHandlerMapping对象呢?
我又Watch了一下beanDefinitionMap里包含的数据:
{
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#0=Root bean: class [org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null,
org.springframework.web.servlet.handler.MappedInterceptor#0=Root bean: class [org.springframework.web.servlet.handler.MappedInterceptor]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null,
org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver#0=Root bean: class [org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null,
mvcContentNegotiationManager=Root bean: class [org.springframework.web.accept.ContentNegotiationManagerFactoryBean]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null,
org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver#0=Root bean: class [org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null,
org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver#0=Root bean: class [org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null,
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#0=Root bean: class [org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null,
org.springframework.format.support.FormattingConversionServiceFactoryBean#0=Root bean: class [org.springframework.format.support.FormattingConversionServiceFactoryBean]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null
}
然后在springmvc的源码中搜索了其中两个beanname
发现都是在org.springframework.web.servlet.config.AnnotationDrivenBeanDefinitionParser这个类中加入到context里的,看这个类应该是跟注解相关的解析类。所以我猜想是不是因为开启了注解驱动的Spring MVC组件模式的原因?
注释掉
<mvc:annotation-driven />注解,再次debug,发现没有走MvcNamespaceUtils类的registerBeanNameUrlHandlerMapping方法,这样系统也就不会生成默认的BeanNameUrlHandlerMapping对象了。
其实从MvcNamespaceUtils类的registerBeanNameUrlHandlerMapping方法调用栈也可以看出来,跟AnnotationDrivenBeanDefinitionParser这个类是有关系的:
然后我又试了保留
<mvc:annotation-driven />注解,注释掉自己设置的BeanNameUrlHandlerMapping,发现请求可以匹配上已经把name设置成url的controller组件。
说明系统开启了注解驱动的Spring MVC组件模式情况下生成的默认的BeanNameUrlHandlerMapping对象,用于处理Web请求与xml配置的具体请求处理控制器之间的映射匹配,是个中间人角色,也会作为Web请求和注解配置的controller组件的中间人。至于为什么会在这种情况下生成默认的BeanNameUrlHandlerMapping对象,我觉得应该是为了在使用注解配置的BeanName类型的controller时,不需要再关心HandlerMapping的问题,毕竟BeanNameUrlHandlerMapping是个底层对象,不需要再对其进行继承重写或者组合到其他对象中,那就启动的时候默认生成一个就好了。
所以如果开启了注解驱动的Spring MVC组件模式,就不需要手动在xml中配置BeanNameUrlHandlerMapping。
相关文章推荐
- Spring MVC的handlermapping之请求分发如何找到正确的Handler(BeanNameUrlHandlerMapping,SimpleUrlHandlerMapping)
- Spring MVC: step by step 5-BeanNameUrlHandlerMapping(我的最爱)
- Spring mvc (五) [ControllerClassNameHandlerMapping根据Controller类名匹配,解决了bean的递增配置问题]
- spring mvc的HandlerMapping的使用之--BeanNameUrlHandlerMapping
- spring mvc基础篇(五):映射处理器之BeanNameUrlHandlerMapping
- Spring MVC-处理程序映射(Handler Mapping)-Bean名称Url处理程序映射(Bean Name Url Handler Mapping)示例(转载实践)
- spring mvc为何多注入了个SimpleUrlHandlerMapping?
- springMVC源码分析--BeanNameUrlHandlerMapping(七)
- Error creating bean with name 'simpleUrlHandlerMapping' defined in ServletContext resource [/WEB-IN
- SpringMVC默认依赖Bean:BeanNameUrlHandlerMapping
- HandlerMapping和BeanNameUrlHandlerMapping的使用
- springMVC源码分析--BeanNameUrlHandlerMapping(七)
- Spring MVC中使用SimpleUrlHandlerMapping映射处理器的一个简单例子
- Spring Web MVC 的HandlerMapping的使用之-------BeanNameUrlHandlerMapping
- springMVC源码分析--BeanNameUrlHandlerMapping(七)
- Spring MVC BeanNameUrlHandlerMapping example
- Spring MVC BeanNameUrlHandlerMapping example
- Spring MVC:使用SimpleUrlHandlerMapping的一个简单例子
- HandlerMapping和BeanNameUrlHandlerMapping的使用
- Spring MVC:使用SimpleUrlHandlerMapping的一个简单例子