SpringMVC写注释c程序中注释部分时RequestMappingHandlerMapping无法初始化这是什么原因?

&springmvc中配置这个标签默认注册三个bean:RequestMappingHandlerMapping,RequestMappingHandlerAdapter,DefaultHandlerExceptionResolver
RequestMappingHandlerMapping
我们看它实现了InitializingBean&接口,所以在getBean()实例化它时会执行afterPropertiesSet()方法,来看该方法干了什么?
方法中实例化了一个BuilderConfiguration对象,并为该对象设置了一些路径抓取器,路径方法匹配器等。最后还需要调用父类的方法
父类只是调用了initHandlerMethods()方法,该方法很关键是将请求路径和方法匹配的
// 获得所有的beanName
// 遍历所有的beanName并获得type类型
// 判断类是否被@Controller或是@RequestMapping注释了,是执行detectHandlerMethods(beanName)方法
&// 首先获得类型class,根据类的class获得一个Map,这个map的key是Method,value是RequestMappingInfo,后文详解#1
&// 遍历map,获得Method和RequestMappingInfo,注册他们。后文详解#2
书接前文#1
&selectMethods()方法中,根据类的class获得所有的方法,遍历方法执行doWith(Method method)方法
获得方法和RequestMappingInfo,将他们存到Map中返回,RequestMappingInfo是怎么获得的呢?我们马上来看
执行的是detectHandlerMethods()方法中的getMappingForMethod(method, userType)方法,该方法是一个抽象方法。RequestMappingHandlerMapping执行方法
// 创建方法的RequestMappingInfo,后文详解#1-1
// 创建类的RequestMappingInfo,该步骤和上一步如出一辙
// 将前两者结合,后文详解#1-2
&书接前文#1-1
// 获得方法上的@RequestMapping注解的信息,根据注解创建RequestMappingInfo
&这里使用了建造者模式创建,我们来看build()方法干了什么?
方法中关键的是PatternsRequestCondition对象,该对象的patterns属性保存了方法注解的路径值如 /app,创建了RequestMappingInfo返回
书接前文#1-2
方法中分别使用结合方法,然后重新创建一个返回,我们主要来看一下PatternsRequestCondition的方法
使用了AntPathMatcher对象结合类注解路径和方法注解路径,如果没有通配符则简单拼接如 /person , /list --& /person/list
重新创建一个返回
&书接前文#2
AbstractHandlerMethodMapping中使用MappingRegistry属性对象注册
&// 创建HandlerMethod对象,后文详解#2-1
// 将映射和对应的方法存起来
&// 获得映射路径,将映射路径和映射对象存起来。后文详解#2-2
// 获得RequestMappingInfo的name,将name和method存起来
&// 将映射对象和映射注册对象存起来
书接前文#2-1
HandlerMethod中,有beanName,beanFactory,method,methodParameter
书接前文#2-2
获得RequestMappingInfo中的PatternsRequestCondition中的patterns属性值
&至此RequestMappingHandlerMapping的初始化完成了
阅读(...) 评论()博客分类:
与SpringSecurity的配置类似,spring同样为我们提供了一个实现类WebMvcConfigurationSupport和一个注解@EnableWebMvc以帮助我们减少bean的声明。
applicationContext-MvcConfig.xml
&!-- 启用注解,并定义组件查找规则 ,mvc层只负责扫描@Controller --&
&context:component-scan base-package="web.function"
use-default-filters="false"&
&context:include-filter type="annotation"
expression="org.springframework.stereotype.Controller" /&
&/context:component-scan&
&!-- 视图处理器 --&
&bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver"&
&property name="prefix" value="/WEB-INF/views/jsp/function/" /&
&property name="suffix" value=".jsp" /&
&!-- 定义国际化资源文件查找规则 ,各种messages.properties --&
&bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource"
p:basename="config.messages.messages"&
&!-- servlet适配器,这里必须明确声明,因为spring默认没有初始化该适配器 --&
&bean id="servletHandlerAdapter"
class="org.springframework.web.servlet.handler.SimpleServletHandlerAdapter" /&
&!-- 定义文件上传处理器 --&
&bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver"
p:defaultEncoding="UTF-8" /&
&!-- 异常处理器 --&
&bean id="exceptionResolver" class="web.core.CP_SimpleMappingExceptionResolver"&
&property name="defaultErrorView" value="common_error" /&
&property name="exceptionAttribute" value="exception" /&
&property name="exceptionMappings"&
&prop key="java.lang.RuntimeException"&common_error&/prop&
&/property&
&!-- 定义公共参数初始化拦截器 --&
&bean id="initInterceptor" class="web.core.CP_InitializingInterceptor" /&
&!-- 本地化资源处理器 --&
&bean id="localeResolver"
class="org.springframework.web.servlet.i18n.CookieLocaleResolver" /&
&!-- 定义本地化变更拦截器 --&
&bean id="localeChangeInterceptor"
class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor" /&
&!-- 请求拦截器,每一个用户请求都会被拦截 --&
&mvc:interceptors&
&ref bean="localeChangeInterceptor" /&
&ref bean="initInterceptor" /&
&/mvc:interceptors&
&!-- 定义注解驱动Controller方法处理适配器 ,注:该适配器必须声明在&mvc:annotation-driven /&之前,否则不能正常处理参数类型的转换 --&
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"&
&property name="webBindingInitializer"&
&bean class="web.core.CP_PropertyEditorRegistrar"&
&property name="format" value="yyyy-MM-dd"&&/property&
&/property&
&property name="messageConverters"&
class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter" /&
class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" /&
&/property&
&!-- 会自动注册RequestMappingHandlerMapping与RequestMappingHandlerAdapter
两个bean,是spring MVC为@Controllers分发请求所必须的。 并提供了:数据绑定支持,@NumberFormatannotation支持,@DateTimeFormat支持,@Valid支持,读写XML的支持(JAXB),读写JSON的支持(Jackson) --&
&mvc:annotation-driven /&
&!-- 资源访问处理器 --&
&mvc:resources mapping="/static/**" location="/WEB-INF/static/" /&
MvcConfig.java
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "web.function", useDefaultFilters = false, includeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, value = {Controller.class})
public class MvcConfig extends WebMvcConfigurationSupport {
private static final Logger logger = Logger
.getLogger(MvcConfig.class);
* 描述 : &注册试图处理器&. &br&
&使用方法说明&
public ViewResolver viewResolver() {
logger.info("ViewResolver");
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/views/jsp/function/");
viewResolver.setSuffix(".jsp");
return viewR
* 描述 : &注册消息资源处理器&. &br&
&使用方法说明&
public MessageSource messageSource() {
logger.info("MessageSource");
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("config.messages.messages");
return messageS
* 描述 : &注册servlet适配器&. &br&
&只需要在自定义的servlet上用@Controller("映射路径")标注即可&
public HandlerAdapter servletHandlerAdapter(){
logger.info("HandlerAdapter");
return new SimpleServletHandlerAdapter();
* 描述 : &本地化拦截器&. &br&
&使用方法说明&
public LocaleChangeInterceptor localeChangeInterceptor(){
logger.info("LocaleChangeInterceptor");
return new LocaleChangeInterceptor();
* 描述 : &基于cookie的本地化资源处理器&. &br&
&使用方法说明&
@Bean(name="localeResolver")
public CookieLocaleResolver cookieLocaleResolver(){
logger.info("CookieLocaleResolver");
return new CookieLocaleResolver();
* 描述 : &注册自定义拦截器&. &br&
&使用方法说明&
public CP_InitializingInterceptor initializingInterceptor(){
logger.info("CP_InitializingInterceptor");
return new CP_InitializingInterceptor();
* 描述 : &RequestMappingHandlerMapping需要显示声明,否则不能注册自定义的拦截器&. &br&
&这个比较奇怪,理论上应该是不需要的&
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
logger.info("RequestMappingHandlerMapping");
return super.requestMappingHandlerMapping();
* 描述 : &添加拦截器&. &br&
&使用方法说明&
* @param registry
protected void addInterceptors(InterceptorRegistry registry) {
// TODO Auto-generated method stub
logger.info("addInterceptors start");
registry.addInterceptor(localeChangeInterceptor());
registry.addInterceptor(initializingInterceptor());
logger.info("addInterceptors end");
* 描述 : &HandlerMapping需要显示声明,否则不能注册资源访问处理器&. &br&
&这个比较奇怪,理论上应该是不需要的&
public HandlerMapping resourceHandlerMapping() {
logger.info("HandlerMapping");
return super.resourceHandlerMapping();
* 描述 : &资源访问处理器&. &br&
&可以在jsp中使用/static/**的方式访问/WEB-INF/static/下的内容&
* @param registry
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
logger.info("addResourceHandlers");
registry.addResourceHandler("/static/**").addResourceLocations("/WEB-INF/static/");
* 描述 : &文件上传处理器&. &br&
&使用方法说明&
@Bean(name="multipartResolver")
public CommonsMultipartResolver commonsMultipartResolver(){
logger.info("CommonsMultipartResolver");
return new CommonsMultipartResolver();
* 描述 : &异常处理器&. &br&
&系统运行时遇到指定的异常将会跳转到指定的页面&
@Bean(name="exceptionResolver")
public CP_SimpleMappingExceptionResolver simpleMappingExceptionResolver(){
logger.info("CP_SimpleMappingExceptionResolver");
CP_SimpleMappingExceptionResolver simpleMappingExceptionResolver= new CP_SimpleMappingExceptionResolver();
simpleMappingExceptionResolver.setDefaultErrorView("common_error");
simpleMappingExceptionResolver.setExceptionAttribute("exception");
Properties properties = new Properties();
properties.setProperty("java.lang.RuntimeException", "common_error");
simpleMappingExceptionResolver.setExceptionMappings(properties);
return simpleMappingExceptionR
* 描述 : &RequestMappingHandlerAdapter需要显示声明,否则不能注册通用属性编辑器&. &br&
&这个比较奇怪,理论上应该是不需要的&
public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
logger.info("RequestMappingHandlerAdapter");
return super.requestMappingHandlerAdapter();
* 描述 : &注册通用属性编辑器&. &br&
&这里只增加了字符串转日期和字符串两边去空格的处理&
protected ConfigurableWebBindingInitializer getConfigurableWebBindingInitializer() {
logger.info("ConfigurableWebBindingInitializer");
ConfigurableWebBindingInitializer initializer = super.getConfigurableWebBindingInitializer();
CP_PropertyEditorRegistrar register = new CP_PropertyEditorRegistrar();
register.setFormat("yyyy-MM-dd");
initializer.setPropertyEditorRegistrar(register);
:代码下载
浏览 68320
hanqunfeng
浏览: 1319901 次
来自: 北京
您好,我用您的方法通过java api往jira系统中添加is ...
可以了,是因为没加intercept-url 的拦截, 尼玛, ...
请问为什么我配了security.xml后切入点不起作用(之前 ...
根据楼主的代码 继承了WebMvcConfigurationS ...
MvcConfig.java的FilterType.ANNOT ...
(window.slotbydup=window.slotbydup || []).push({
id: '4773203',
container: s,
size: '200,200',
display: 'inlay-fix'SpringMVC源码解读之HandlerMapping
&更新时间:日 09:31:18 & 作者:出门向左
这篇文章主要介绍了SpringMVC源码解读之HandlerMapping 的相关资料,需要的朋友可以参考下
对于Web开发者,MVC模型是大家再熟悉不过的了,SpringMVC中,满足条件的请求进入到负责请求分发的DispatcherServlet,DispatcherServlet根据请求url到控制器的映射(HandlerMapping中保存),HandlerMapping最终返回HandlerExecutionChain,其中包含了具体的处理对象handler(也即我们编程时写的controller)以及一系列的拦截器interceptors,此时DispatcherServlet会根据返回的HandlerExecutionChain中的handler找到支持这一处理器类型的适配器(handlerAdapter),在处理器适配器中最终会去调用控制器的请求响应方法并返回结果视图(ModelAndView),得到结果视图后,通过render方法完成结果的显示。
HanderMapping的继承体系:
SpringMVC在请求到handler处理器的分发这步是通过HandlerMapping模块解决的.handlerMapping 还处理拦截器.
先看看HandlerMapping的继承树吧
可以大致这样做个分类:
  1. 一个接口HandlerMapping,定义一个api: HandlerExecutionChain getHandler(HttpServletRequest request) throws E
  2. 一个基础抽象类:主要是准备上下文环境,提供getHandlerInternal钩子,封装拦截器到HandlerExecutionChain
  3. 基于注解@Controller,@RequestMapping的使用
  4. 配置文件中直接配置url到 handler的SimpleUrlHandlerMapping
  5. 默认实现BeanNameUrlHandlerMapping
  6. Controller子类的映射
看看HandlerMapping吧,就一个getHandler api 非常简单.
// HandlerMapping
package org.springframework.web.
public interface HandlerMapping {
HandlerExecutionChain getHandler(HttpServletRequest request) throws E
AbstractHandlerMapping就没有这么简单了
先看AbstractHandlerMapping继承的类,实现的接口
package org.springframework.web.servlet.
public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport
implements HandlerMapping, Ordered {
WebApplicationObjectSupport用于提供上下文ApplicationContext和ServletContext.
  还有这边的initApplicationContext方法,在后续经常会使用到.AbstractHandlerMapping就直接覆写了.
  父类里还是实现了ApplicationContextAware和ServletContextAware接口,spring概念很统一.
Ordered用于集合排序.
再接着看AbstractHandlerMapping的属性吧
// AbstractHandlerMapping
// order赋了最大值,优先级是最小的
private int order = Integer.MAX_VALUE; // default: same as non-Ordered
// 默认的Handler,这边使用的Obejct,子类实现的时候,使用HandlerMethod,HandlerExecutionChain等
private Object defaultH
// url计算的辅助类
private UrlPathHelper urlPathHelper = new UrlPathHelper();
// 基于ant进行path匹配,解决如/books/{id}场景
private PathMatcher pathMatcher = new AntPathMatcher();
// 拦截器配置:,HandlerMapping属性设置;,extendInterceptors设置
private final List&Object& interceptors = new ArrayList&Object&();
// 从interceptors中解析得到,直接添加给全部handler
private final List&HandlerInterceptor& adaptedInterceptors = new ArrayList&HandlerInterceptor&();
// 使用前需要跟url进行匹配,匹配通过才会使用
private final List&MappedInterceptor& mappedInterceptors = new ArrayList&MappedInterceptor&();
看下拦截器的初始化:
// AbstractHandlerMapping
protected void initApplicationContext() throws BeansException {
extendInterceptors(this.interceptors);
detectMappedInterceptors(this.mappedInterceptors);
initInterceptors();
* 提供给子类扩展拦截器,可惜都没有使用
protected void extendInterceptors(List&Object& interceptors) {
* 扫描应用下的MappedInterceptor,并添加到mappedInterceptors
protected void detectMappedInterceptors(List&MappedInterceptor& mappedInterceptors) {
mappedInterceptors.addAll(
BeanFactoryUtils.beansOfTypeIncludingAncestors(
getApplicationContext(),MappedInterceptor.class, true, false).values());
* 归集MappedInterceptor,并适配HandlerInterceptor和WebRequestInterceptor
protected void initInterceptors() {
if (!this.interceptors.isEmpty()) {
for (int i = ; i & this.interceptors.size(); i++) {
Object interceptor = this.interceptors.get(i);
if (interceptor == null) {
throw new IllegalArgumentException("Entry number " + i + " in interceptors array is null");
if (interceptor instanceof MappedInterceptor) {
mappedInterceptors.add((MappedInterceptor) interceptor);
adaptedInterceptors.add(adaptInterceptor(interceptor));
protected HandlerInterceptor adaptInterceptor(Object interceptor) {
if (interceptor instanceof HandlerInterceptor) {
return (HandlerInterceptor)
else if (interceptor instanceof WebRequestInterceptor) {
return new WebRequestHandlerInterceptorAdapter((WebRequestInterceptor) interceptor);
throw new IllegalArgumentException("Interceptor type not supported: " + interceptor.getClass().getName());
然后是getHandler(HttpServletRequest request)的实现,这边同时预留getHandlerInternal(HttpServletRequest request)给子类实现
// AbstractHandlerMapping
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
Object handler = getHandlerInternal(request);
if (handler == null) {
handler = getDefaultHandler();
if (handler == null) {
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String)
handler = getApplicationContext().getBean(handlerName);
return getHandlerExecutionChain(handler, request);
protected abstract Object getHandlerInternal(HttpServletRequest request) throws E
最后是封装拦截器到HandlerExecutionChain
  adaptedInterceptors直接添加
  mappedInterceptors需要根据url匹配通过后添加
// AbstractHandlerMapping
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
HandlerExecutionChain chain =
(handler instanceof HandlerExecutionChain) ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler);
chain.addInterceptors(getAdaptedInterceptors());
String lookupPath = urlPathHelper.getLookupPathForRequest(request);
for (MappedInterceptor mappedInterceptor : mappedInterceptors) {
if (mappedInterceptor.matches(lookupPath, pathMatcher)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
Controller子类的映射,这一分支先看类继承
我们来说说,这边每个类主要的职责
  1. AbstractHandlerMapping 准备上下文环境;提供getHandlerInternal钩子;封装拦截器到HandlerExecutionChain
  2. AbstractUrlHandlerMapping 实现注册handler的方法供子类使用;实现getHandlerInternal,根据子类初始化的配置信息,查找handler
  3. AbstractDetectingUrlHandlerMapping 扫描应用下的Object,迭代后提供钩子方法determineUrlsForHandler由子类决定如何过滤
  4. AbstractControllerUrlHandlerMapping 实现determineUrlsForHandler,添加过滤排除的handler操作(配置文件配置),预留钩子方法buildUrlsForHandler给子类实现;同时判断controller的子类
  5. ControllerBeanNameHandlerMapping 根据bean name生成url
    ControllerClassNameHandlerMapping根据class name生成url
从AbstractUrlHandlerMapping开始看吧,这边只是大致看下代码,如果需要仔细分析,请移步
handler的注册
protected void registerHandler(String[] urlPaths, String beanName) throws BeansException, IllegalStateException { }
protected void registerHandler(String urlPath, Object handler) throws BeansException, IllegalStateException { }
handler的查找
protected Object getHandlerInternal(HttpServletRequest request) throws Exception {}
// 根据url查找handler
protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {}
// 校验handler
protected void validateHandler(Object handler, HttpServletRequest request) throws Exception {}
// 封装拦截器到HandlerExecutionChain
protected Object buildPathExposingHandler(Object rawHandler, String bestMatchingPattern,
String pathWithinMapping, Map&String, String& uriTemplateVariables) {}
AbstractDetectingUrlHandlerMapping,这边一样不展开,具体移步
具体做的事情:
  1. 通过覆写initApplicationContext,调用detectHandlers扫描Obejct
  2. 提供钩子方法determineUrlsForHandler给子类根据handler生成url
  3. 调用父类的registerHandler进行注册
public void initApplicationContext() throws ApplicationContextException {
super.initApplicationContext();
detectHandlers();
protected void detectHandlers() throws BeansException {
* Determine the URLs for the given handler bean.
* 钩子而已
protected abstract String[] determineUrlsForHandler(String beanName);
AbstractControllerUrlHandlerMapping,这边一样不展开,具体移步&SpringMVC源码解读 - HandlerMapping - AbstractDetectingUrlHandlerMapping系列初始化&
具体做的事情;
  1. 覆写determineUrlsForHandler添加剔除部分类的逻辑,通过配置文件配置的excludedClasses和excludedPackages在这边使用
  2. 判断是否controller的子类
  3. 预留buildUrlsForHandler给子类生成url
protected String[] determineUrlsForHandler(String beanName) {
Class beanClass = getApplicationContext().getType(beanName);
if (isEligibleForMapping(beanName, beanClass)) {
return buildUrlsForHandler(beanName, beanClass);
protected boolean isEligibleForMapping(String beanName, Class beanClass) {}
protected boolean isControllerType(Class beanClass) {}
protected abstract String[] buildUrlsForHandler(String beanName, Class beanClass);
ControllerBeanNameHandlerMapping和ControllerClassNameHandlerMapping 直接看源码吧,或者移步&SpringMVC源码解读 - HandlerMapping - AbstractDetectingUrlHandlerMapping系列初始化&
配置文件中直接配置url到 handler的SimpleUrlHandlerMapping,就是使用registerHandlers注册配置文档中的handler,直接看代码或者移步&SpringMVC源码解读 - HandlerMapping - SimpleUrlHandlerMapping初始化&吧
BeanNameUrlHandlerMapping 实现determineUrlsForHandler生成url,直接看代码或者移步&SpringMVC源码解读 - HandlerMapping - AbstractDetectingUrlHandlerMapping系列初始化&吧
基于注解@Controller,@RequestMapping的使用
最难吭的骨头
先看类继承吧
说下各个类的职责吧,具体的分析还是移步下面的文章
&SpringMVC源码解读 - HandlerMapping - RequestMappingHandlerMapping初始化&
&SpringMVC源码解读 - HandlerMapping - RequestMappingHandlerMapping请求分发&
  1. AbstractHandlerMethodMaping 定义初始化流程,请求时如何映射
  初始化:
    1.1.1 扫描应用下的Object
    1.1.2 预留isHandler钩子方法给子类判断Object是否handler
    1.1.3 迭代扫描每一个handler,找出符合要求的方法,这边判断依然是留给子类实现getMappingForMethod
    1.1.4 注册查找到的处理器,需要确保一个匹配条件RequestMappingInfo只能映射到一个handler
    1.1.5 根据匹配条件获取url,同样的只是定义流程,具体的算法留给子类实现getMappingPathPatterns
  请求request分发处理:
    1.2.1 直接字符串匹配的方式,查找handler 
    1.2.2 匹配条件查找,这边具体的算法交由子类处理getMatchingMapping
    1.2.3 排序并获取最佳匹配handler,这边的排序方式还是子类处理getMappingConmparator
   1.2.4 分别封装匹配到和未匹配到handler的情况
  2. RequestMappingInfoHandlerMapping使用RequestMappingInfo实现匹配条件,RequestMappingInfo的初始化留给子类
    2.1 根据RequestMappingInfo生成url -&getMappingPathPatterns
    2.2 使用匹配条件查找Handler -& getMatchingMapping
    2.3 完成比较器算法 -& getMappingComparator
    2.4 覆写handleMatch,缓存n多信息到request
      注册pattern,最佳匹配的pattern,url中解析出来的参数,url中解析出来的多值参数,mediaType
    2.1.5 覆写handlerNoMatch,最后的挣扎,再尝试匹配一次
  3. RequestMappingHandlerMapping 根据注解@Controller @RequestMapping生成RequestMappingInfo,并校验isHandler
    3.1 覆写afterPropertiesSet,添加文件后缀判断
    3.2 实现isHandler,类上有@Controller @RequestMapping其中一个注解就对
    3.3 解析注解内容,生产RequestMappingInfo实例
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具}

我要回帖

更多关于 程序注释 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信