SpringMVC之分析RequestMappingHandlerAdapter(一)
来源:互联网 发布:淘宝怎么评价卖家 编辑:程序博客网 时间:2024/06/08 03:42
RequestMappingHandlerAdapter请求映射处理适配器,在SpringMVC中它是一个非常重要的类,对请求处理方法的调用主要是通过这个类来完成的(这段代码mv = ha.handle(processedRequest, response, mappedHandler.getHandler());)。下面我们就简单的分析一下这个类。首先我们先看一下它的UML类图结构:
画红线的部分是需要我们注意的一些类,如果你对Spring的Bean生命在周期熟悉的话,你会发现这些都是Spring的Bean生命周期相关的一些类(Spring Bean的生命周期小析(一)和Spring Bean的生命周期小析(二))。我们分析RequestMappingHandlerAdapter的时候也会从这些接口的实现方法中开始。首先我们先看一下它的构造函数:
public RequestMappingHandlerAdapter() {StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter();stringHttpMessageConverter.setWriteAcceptCharset(false); // see SPR-7316this.messageConverters = new ArrayList<HttpMessageConverter<?>>(4);this.messageConverters.add(new ByteArrayHttpMessageConverter());this.messageConverters.add(stringHttpMessageConverter);this.messageConverters.add(new SourceHttpMessageConverter<Source>());this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());}从上面的代码中我们可以看到这里默认添加了四种类型的Http数据转换器。其中我们需要关注的时候AllEncompassingFormHttpMessageConverter这个转换器,我们也去它的构造函数中看一下:
public AllEncompassingFormHttpMessageConverter() {addPartConverter(new SourceHttpMessageConverter<Source>());//如果Classpath下面有javax.xml.bind.Binder类,//没有com.fasterxml.jackson.dataformat.xml.XmlMapper类的话//则添加Jaxb2RootElementHttpMessageConverter转换器if (jaxb2Present && !jackson2XmlPresent) {addPartConverter(new Jaxb2RootElementHttpMessageConverter());}//如果Classpath下有com.fasterxml.jackson.databind.ObjectMapper//和com.fasterxml.jackson.core.JsonGenerator的话,则添加//MappingJackson2HttpMessageConverter转换器if (jackson2Present) {addPartConverter(new MappingJackson2HttpMessageConverter());}//如果Classpath下面有com.google.gson.Gson类的话,则添加//GsonHttpMessageConverter转换器else if (gsonPresent) {addPartConverter(new GsonHttpMessageConverter());}//如果Classpath下有com.fasterxml.jackson.dataformat.xml.XmlMapper类的话,//则添加MappingJackson2XmlHttpMessageConverter转换器if (jackson2XmlPresent) {addPartConverter(new MappingJackson2XmlHttpMessageConverter());}}其实在它的父类中还添加了三种类型的Convert:
public FormHttpMessageConverter() {//application/x-www-form-urlencodedthis.supportedMediaTypes.add(MediaType.APPLICATION_FORM_URLENCODED);//multipart/form-datathis.supportedMediaTypes.add(MediaType.MULTIPART_FORM_DATA);//ByteArrayHttpMessageConverterthis.partConverters.add(new ByteArrayHttpMessageConverter());StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter();stringHttpMessageConverter.setWriteAcceptCharset(false);//StringHttpMessageConverterthis.partConverters.add(stringHttpMessageConverter);//ResourceHttpMessageConverterthis.partConverters.add(new ResourceHttpMessageConverter());applyDefaultCharset();}按照Spring的Bean的生命周期的执行顺序,这里会先调用BeanFactoryAware#setBeanFactory方法、接着调用ApplicationContextAware#setApplicationContext方法,最后调用InitializingBean#afterPropertiesSet方法。我们先看一下重写之后的setBeanFactory方法的源码:
@Overridepublic void setBeanFactory(BeanFactory beanFactory) {if (beanFactory instanceof ConfigurableBeanFactory) {this.beanFactory = (ConfigurableBeanFactory) beanFactory;}}这个方法的内容很简单,就是设置一下beanFactory的属性值(其实这里的beanFactory是DefaultListableBeanFactory的实例)。
下面我们看一下setApplicationContext这个方法的源码,这个方法藏的比较深,在它的父类ApplicationObjectSupport#setApplicationContext方法中。
public final void setApplicationContext(ApplicationContext context) throws BeansException {//isContextRequired()方法返回trueif (context == null && !isContextRequired()) {// Reset internal context state.this.applicationContext = null;this.messageSourceAccessor = null;}else if (this.applicationContext == null) {// Initialize with passed-in context.//所传入的context如果不能被实例化,则抛出异常if (!requiredContextClass().isInstance(context)) {throw new ApplicationContextException("Invalid application context: needs to be of type [" + requiredContextClass().getName() + "]");}this.applicationContext = context;//国际化this.messageSourceAccessor = new MessageSourceAccessor(context);//初始化ApplicationContextinitApplicationContext(context);}else {// Ignore reinitialization if same context passed in.if (this.applicationContext != context) {throw new ApplicationContextException("Cannot reinitialize with different application context: current one is [" +this.applicationContext + "], passed-in one is [" + context + "]");}}}我们主要看一下WebApplicationObjectSupport#initApplicationContext这个方法的内容:
@Overrideprotected void initApplicationContext(ApplicationContext context) {//调用父类中的initApplicationContext方法super.initApplicationContext(context);if (this.servletContext == null && context instanceof WebApplicationContext) {this.servletContext = ((WebApplicationContext) context).getServletContext();if (this.servletContext != null) {//初始化ServletContextinitServletContext(this.servletContext);}}}这里先调用父类中的initApplicationContext方法,然后会初始ServletContext。先看一下ApplicationObjectSupport#initApplicationContext方法:
protected void initApplicationContext(ApplicationContext context) throws BeansException {initApplicationContext();}在我们的这个类的继承体系中,initApplicationContext();是一个空实现。同样initServletContext也是一个空实现。接下来我们要分析的一个重点InitializingBean#afterPropertiesSet的方法,它的源码内容如下,下面我们一点一点的分析这个类:
public void afterPropertiesSet() {// Do this first, it may add ResponseBody advice beansinitControllerAdviceCache();if (this.argumentResolvers == null) {List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);}if (this.initBinderArgumentResolvers == null) {List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);}if (this.returnValueHandlers == null) {List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);}}我们先看initControllerAdviceCache这个方法:
private void initControllerAdviceCache() {//通过上面的分析我们知道,这个方法的内容不为nullif (getApplicationContext() == null) {return;}//获取所有带ControllerAdvice注解的类List<ControllerAdviceBean> beans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());//对获取到的ControllerAdvice注解的类进行排序,排序的规则是基于实现PriorityOrdered接口或者带有Order注解AnnotationAwareOrderComparator.sort(beans);List<Object> requestResponseBodyAdviceBeans = new ArrayList<Object>();//循环获取到的ControllerAdviceBeanfor (ControllerAdviceBean bean : beans) {//获取所有ModelAttribute注解的方法,并且没有RequestMapping注解的方法Set<Method> attrMethods = MethodIntrospector.selectMethods(bean.getBeanType(), MODEL_ATTRIBUTE_METHODS);if (!attrMethods.isEmpty()) {this.modelAttributeAdviceCache.put(bean, attrMethods);if (logger.isInfoEnabled()) {logger.info("Detected @ModelAttribute methods in " + bean);}}//获取所有带InitBinder注解的方法Set<Method> binderMethods = MethodIntrospector.selectMethods(bean.getBeanType(), INIT_BINDER_METHODS);if (!binderMethods.isEmpty()) {this.initBinderAdviceCache.put(bean, binderMethods);if (logger.isInfoEnabled()) {logger.info("Detected @InitBinder methods in " + bean);}}//如果实现了RequestBodyAdvice接口if (RequestBodyAdvice.class.isAssignableFrom(bean.getBeanType())) {requestResponseBodyAdviceBeans.add(bean);if (logger.isInfoEnabled()) {logger.info("Detected RequestBodyAdvice bean in " + bean);}}//如果实现了ResponseBodyAdvice接口if (ResponseBodyAdvice.class.isAssignableFrom(bean.getBeanType())) {requestResponseBodyAdviceBeans.add(bean);if (logger.isInfoEnabled()) {logger.info("Detected ResponseBodyAdvice bean in " + bean);}}}//添加到requestResponseBodyAdvice集合中if (!requestResponseBodyAdviceBeans.isEmpty()) {this.requestResponseBodyAdvice.addAll(0, requestResponseBodyAdviceBeans);}}在这个方法里主要是获取了带ControllerAdvice注解的类,并从这些类中查找实现了RequestBodyAdvice或者ResponseBodyAdvice接口的类,添加到requestResponseBodyAdvice集合中,另外获取所有带ModelAttribute注解且没有RequestMapping注解的方法,放到modelAttributeAdviceCache集合中,获取所有带InitBinder注解的方法放到initBinderAdviceCache的集合中。下面我们再看这一段代码:
if (this.argumentResolvers == null) {List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);}
private HandlerMethodArgumentResolverComposite argumentResolvers;argumentResolvers这个属性是HandlerMethodArgumentResolverComposite 类型的,如果我们在配置RequestMappingHandlerAdapter的时候设置了一系列HandlerMethodArgumentResolver的实现类的话,如下所示,
public void setArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {if (argumentResolvers == null) {this.argumentResolvers = null;}else {this.argumentResolvers = new HandlerMethodArgumentResolverComposite();this.argumentResolvers.addResolvers(argumentResolvers);}}它会先创建HandlerMethodArgumentResolverComposite对象,然后把配置的HandlerMethodArgumentResolver的实现类添加到HandlerMethodArgumentResolverComposite的对象中。这里我们是没有手工配置RequestMappingHandlerAdapter的,所以,会先调用getDefaultArgumentResolvers方法,获取一系列默认的HandlerMethodArgumentResolver的实现类,代码如下:
private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {List<HandlerMethodArgumentResolver> resolvers = new ArrayList<HandlerMethodArgumentResolver>();// Annotation-based argument resolutionresolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));resolvers.add(new RequestParamMapMethodArgumentResolver());resolvers.add(new PathVariableMethodArgumentResolver());resolvers.add(new PathVariableMapMethodArgumentResolver());resolvers.add(new MatrixVariableMethodArgumentResolver());resolvers.add(new MatrixVariableMapMethodArgumentResolver());resolvers.add(new ServletModelAttributeMethodProcessor(false));resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters(), this.requestResponseBodyAdvice));resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));resolvers.add(new RequestHeaderMapMethodArgumentResolver());resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));resolvers.add(new SessionAttributeMethodArgumentResolver());resolvers.add(new RequestAttributeMethodArgumentResolver());// Type-based argument resolutionresolvers.add(new ServletRequestMethodArgumentResolver());resolvers.add(new ServletResponseMethodArgumentResolver());resolvers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));resolvers.add(new RedirectAttributesMethodArgumentResolver());resolvers.add(new ModelMethodProcessor());resolvers.add(new MapMethodProcessor());resolvers.add(new ErrorsMethodArgumentResolver());resolvers.add(new SessionStatusMethodArgumentResolver());resolvers.add(new UriComponentsBuilderMethodArgumentResolver());// Custom argumentsif (getCustomArgumentResolvers() != null) {resolvers.addAll(getCustomArgumentResolvers());}// Catch-allresolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));resolvers.add(new ServletModelAttributeMethodProcessor(true));return resolvers;}SpringMVC为我们自动添加了大概26个HandlerMethodArgumentResolver的实现类。这里有一个方法需要我们注意一下:getCustomArgumentResolvers() 方法。这个方法是用来获取自定义的HandlerMethodArgumentResolver的实现类,也就是说如果我们有自己写的HandlerMethodArgumentResolver的方法的话,我们配置的属性是customArgumentResolvers,最好不要配置argumentResolvers这个属性。然后我们注意的一点是我们所添加的所以的HandlerMethodArgumentResolver的实现类,都是添加到了HandlerMethodArgumentResolverComposite这个类中,HandlerMethodArgumentResolverComposite也是HandlerMethodArgumentResolver的一个实现类。还有一点需要注意的是,这里创建了两个RequestParamMethodArgumentResolver的实例,一个传了true参数,一个传了false参数,这是用来解析不同的请求参数的,详情请看这里:SpringMVC之分析请求对应处理器方法参数的解析过程(一)
阅读全文
0 0
- SpringMVC之分析RequestMappingHandlerAdapter(一)
- SpringMVC之分析RequestMappingHandlerAdapter(二)
- springMVC源码分析--RequestMappingHandlerAdapter(五)
- SpringMVC源码分析(一)之DispatcherServlet
- SpringMVC之分析AnnotationDrivenBeanDefinitionParser(一)
- SpringMVC之分析HandlerMethodReturnValueHandler(一)
- SpringMVC源码分析(一)
- SpringMVC源码分析(一)
- SpringMVC之安全性(一)
- springMVC源码分析--国际化LocaleResolver(一)
- springMVC源码分析--HandlerAdapter(一)
- springMVC源码分析--视图View(一)
- springMVC源码分析--国际化LocaleResolver(一)
- springmvc和mybatis整合 之 一、需求分析
- J2EE系列之SpringMVC学习笔记(一)--SpringMVC简介
- springMVC之ContextLoaderListener分析
- SpringMVC之RequestContextHolder分析
- SpringMVC之RequestContextHolder分析
- Maven 介绍(二)
- Mybatis入门级教程
- fiddler 抓包
- 微信小程序获取input输入框的值
- 深入理解JAVA虚拟机---垃圾收集算法和垃圾收集器
- SpringMVC之分析RequestMappingHandlerAdapter(一)
- 剑指offer之平衡二叉树(Python)
- HDOJ2036_改革春风吹满地
- hasnext()用法
- java 泛型之 通配符的限定 之 extends 的实例
- 存储器名称
- 几何专题的基础算法
- Windows android studio配置ADB环境变量
- bzoj 3611: [Heoi2014]大工程(虚树+树形DP)