SpringMVC源码研究之注解<mvc:annotation-driven />
来源:互联网 发布:淘宝买书靠谱吗 编辑:程序博客网 时间:2024/06/05 18:11
Spring-MVC注解
1. 前言
- 通过查看 spring-webmvc-xxx.jar 下的spring.handlers文件可以发现 mvc前缀的标签都是由
MvcNamespaceHandler
来进行解析的。 - 通过查看其内部唯一的方法
init()
的实现可以确定<mvc:annotation-driven />
的解析工作是由AnnotationDrivenBeanDefinitionParser
类全权负责的。
2. AnnotationDrivenBeanDefinitionParser
其所实现的接口
BeanDefinitionParser
的作用和意义就不再赘述了.
观察该类对所继承接口的实现可以发现:
1. 向SpringMVC容器中注册了 ContentNegotiationManagerFactoryBean
2. 向SpringMVC容器中注册了 RequestMappingHandlerMapping
(间接实现了HandlerMapping
接口), order为0
3. 向SpringMVC容器中注册了 RequestMappingHandlerAdapter
(间接实现了HandlerAdapter
接口,直接实现了InitializingBean
接口,关于这个接口的实现,参见本人的另外一篇博客)
4. 向SpringMVC容器中注册了 MappedInterceptor
5. 向SpringMVC容器中注册了 ExceptionHandlerExceptionResolver
(间接实现了HandlerExceptionResolver
接口), order为0
6. 向SpringMVC容器中注册了 ResponseStatusExceptionResolver
(间接实现了HandlerExceptionResolver
接口), order为1
7. 向SpringMVC容器中注册了 DefaultHandlerExceptionResolver
(间接实现了HandlerExceptionResolver
接口), order为2
2.1 日志分析
以下是从启动日志里提取出来的, 为了注释特意进行了换行, 原本只是一行.
信息: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@d672d2: // SpringMVC容器defining beans [ mvcContentNegotiationManager, // 在AnnotationDrivenBeanDefinitionParser类的getContentNegotiationManager()方法中进行注册 org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#0, // org.springframework.format.support.FormattingConversionServiceFactoryBean#0, // 在AnnotationDrivenBeanDefinitionParser类的getConversionService()方法中进行注册 org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#0, // org.springframework.web.servlet.handler.MappedInterceptor#0, // org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver#0, // org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver#0, // org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver#0, // 以上可以参见上面的解释 org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping, org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter, // org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter, // 以上三个由MvcNamespaceUtils.registerDefaultComponents()方法完成 org.springframework.aop.config.internalAutoProxyCreator, // loginController, // 自定义 userController, // 自定义 org.springframework.context.annotation.internalConfigurationAnnotationProcessor, org.springframework.context.annotation.internalAutowiredAnnotationProcessor, org.springframework.context.annotation.internalRequiredAnnotationProcessor, org.springframework.context.annotation.internalCommonAnnotationProcessor, org.springframework.web.servlet.resource.ResourceHttpRequestHandler#0, // 在spring-mvc.xml中的<mvc:resources /> viewResolver, // 在spring-mvc.xml中注册]; parent: org.springframework.beans.factory.support.DefaultListableBeanFactory@f80021
3. 绑定Handler与Method
信息: Mapped “{[//logout],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}” onto public void cn.springmvc.controller.LoginController.logout(javax.servlet.http.HttpServletResponse,javax.servlet.http.HttpSession)
以上这一句日志信息属于INFO级别; 位置位于 RequestMappingHandlerMapping
类的祖先类AbstractHandlerMethodMapping<T>
内的registerHandlerMethod
方法中.
我们仔细查看RequestMappingHandlerMapping
类的继承链就会发现, 其祖先类 AbstractHandlerMethodMapping<T>
实现了 InitializingBean
, 如此有名的接口我就不多介绍了. 现在就让我们直接查看AbstractHandlerMethodMapping<T>
对该接口的实现吧.
/** * Detects handler methods at initialization. */public void afterPropertiesSet() { initHandlerMethods();}/** * Scan beans in the ApplicationContext, detect and register handler methods. * @see #isHandler(Class) * @see #getMappingForMethod(Method, Class) * @see #handlerMethodsInitialized(Map) */protected void initHandlerMethods() { // this.detectHandlerMethodsInAncestorContexts默认为false // getApplicationContext()获取到的是SpringMVC容器 // 注意我们在spring-mvc.xml中除了键入<mvc:annotation-driven />之外, // 还会键入<context:component-scan base-package="xx.yyy.zzz" />;关于这个自定义标签, 请参见本人的上一篇博客 String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ? BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) : getApplicationContext().getBeanNamesForType(Object.class)); for (String beanName : beanNames) { // isHandler在AbstractHandlerMethodMapping<T>类中抽象方法; // RequestMappingHandlerMapping对其的实现请看下面 if (isHandler(getApplicationContext().getType(beanName))){ // 查看下面的讲解 detectHandlerMethods(beanName); } } handlerMethodsInitialized(getHandlerMethods());}
3.1 isHandler
RequestMappingHandlerMapping
类对祖先类AbstractHandlerMethodMapping<T>
类的实现
// 判断该Bean是否属于Handler,// 关于Controller注解, 其被@Component修饰着, 更多的请参见本人的上一篇博客// 所以这里默认是筛选出所有的我们注册进SpringMVC容器中的标记了@Controller的Bean(例如使用<context:component-scan/>)protected boolean isHandler(Class<?> beanType) { return ((AnnotationUtils.findAnnotation(beanType, Controller.class) != null) || (AnnotationUtils.findAnnotation(beanType, RequestMapping.class) != null));}
3.2 detectHandlerMethods
具体实现位于AbstractHandlerMethodMapping<T>
类中, 详细代码就不贴了. 我们只看其中的重点内容
getMappingForMethod(method, userType)
其中:
1. userType为我们自定义的, 被@Controller注解所修饰的类.
2. method为 java.lang.reflect.Method
类型, 为我们所自定义的userType类型中的方法.
3. 该getMappingForMethod
方法也是抽象的, 交由RequestMappingHandlerMapping
类来实现.
registerHandlerMethod(handler, method, mappings.get(method));
其中:
1. handler为传入的bean name
2. method为 java.lang.reflect.Method
类型, 为我们所自定义的userType类型中的方法.
3. mappings.get(method)为我们使用getMappingForMethod
构造的RequestMappingInfo
实例
3.3 getMappingForMethod
由RequestMappingHandlerMapping
类进行实现
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) { RequestMappingInfo info = null; // 抽取该方法上注解的@RequestMapping RequestMapping methodAnnotation = AnnotationUtils.findAnnotation(method, RequestMapping.class); if (methodAnnotation != null) { // getCustomMethodCondition默认返回null RequestCondition<?> methodCondition = getCustomMethodCondition(method); info = createRequestMappingInfo(methodAnnotation, methodCondition); // 抽取handlerType(即我们自定义的Controller类)上注解的@RequestMapping RequestMapping typeAnnotation = AnnotationUtils.findAnnotation(handlerType, RequestMapping.class); // 如果该方法所在的类也有@RequestMapping信息, 则进行合并 if (typeAnnotation != null) { RequestCondition<?> typeCondition = getCustomTypeCondition(handlerType); // 合并两个RequestMapping的信息 info = createRequestMappingInfo(typeAnnotation, typeCondition).combine(info); } } return info;}
3.4 createRequestMappingInfo
具体实现位于RequestMappingHandlerMapping
类
protected RequestMappingInfo createRequestMappingInfo( RequestMapping requestMapping, RequestCondition<?> customCondition) { return RequestMappingInfo .paths(resolveEmbeddedValuesInPatterns(requestMapping.path())) /* 这里说明我们是可以在配置@RequestMapping时, 使用spel表达式的; 例如@RequestMapping("/yuyue/${url.mh}/login") */ .methods(requestMapping.method()) .params(requestMapping.params()) .headers(requestMapping.headers()) .consumes(requestMapping.consumes()) .produces(requestMapping.produces()) .mappingName(requestMapping.name()) .customCondition(customCondition) .options(this.config) .build();}
3.5 registerHandlerMethod
对上面抽取出来RequestMappingInfo
信息 注册到 LinkedHashMap<RequestMappingInfo,HandlerMethod>
类型的全局字段handlerMethods
和全局字段LinkedMultiValueMap<String, RequestMappingInfo>
类型的全局字段urlMap中.
4. 引用
依然是CSDN推送的文章
1. mvc:resources拦截资源显示问题
2. mvc:annotation-driven中的HandlerMethodReturnValueHandler
- SpringMVC源码研究之注解<mvc:annotation-driven />
- SpringMVC之mvc:annotation-driven
- SpringMVC-->mvc:annotation-driven
- SpringMVC 解读之<mvc:annotation-driven/>标签
- SpringMVC 解读之<mvc:annotation-driven/>标签
- <mvc:annotation-driven />注解意义
- <mvc:annotation-driven />注解意义
- <mvc:annotation-driven />注解意义
- <mvc:annotation-driven />注解意义
- <mvc:annotation-driven />注解意义
- <mvc:annotation-driven />注解意义
- <mvc:annotation-driven />注解意义
- <mvc:annotation-driven/>注解意义
- <mvc:annotation-driven />注解意义
- <mvc:annotation-driven />注解意义
- <mvc:annotation-driven />注解意义
- <mvc:annotation-driven />注解意义
- <mvc:annotation-driven />注解意义
- 10.4离线赛
- 取消WPS自动编号问题
- ROS04-基础知识-工具
- Gym 101142F Folding
- .NET 操作MongoDB入门(一) 安装MongoDB
- SpringMVC源码研究之注解<mvc:annotation-driven />
- Lintcode python之两数组的交
- javaSE之方法反射调用
- MFCC原理及代码
- 近似排列计数
- Gym 101142K King's Heir
- Java基本数据类型——Java基本数据类型汇总、自动类型转换(指导图)、强制类型转型乱码问题、运算时类型提升容易犯的错误常见问题汇总
- MLaPP Chapter 2 Probability 概率论
- 关于枚举式单例的一些详解