<mvc:annotation-driven/>

问题

前端添加一个上传图片的控件,后端用MultipartHttpServletRequest强转request时,报406错误。

406 NOT ACCEPTABLE
The target resource does not have a current representation that would be acceptable to the user agent, according to the proactive negotiation header fields received in the request1, and the server is unwilling to supply a default representation.

解决方法,在appcontex-mvc.xml 加上<mvc:annotation-driven/>

AnnotationDrivenBeanDefinitionParser

通常如果我们希望通过注解的方式来进行SpringMVC开发,我们都会在*-servlet.xml中加入<mvc:annotation-driven/>标签来告诉spring我们的目的。但是我们为什么这么做呢?这个标签是什么意思呢?它做了什么呢?

同样为了弄清楚这些问题, 像<context:component-scan/>标签一样,我们先找到它的解析类。第一篇文章中说过了,所有的自定义命名空间(像mvc,context等)下的标签解析都是由BeanDefinitionParser接口的子类来完成的。
这里写图片描述

我们看到有多个AnnotationDrivenBeanDefinitionParser,他们是用来处理不同命名空间下的<annotation-driven/>标签的,我们今天研究的是<mvc:annotation-driven/>标签,所以我们找到对应的实现类是org.springframework.web.servlet.config.AnnotationDrivenBeanDefinitionParser
通过阅读类注释文档,我们发现这个类主要是用来向工厂中注册了

RequestMappingHandlerMapping 
BeanNameUrlHandlerMapping

RequestMappingHandlerAdapter
HttpRequestHandlerAdapter
SimpleControllerHandlerAdapter

ExceptionHandlerExceptionResolver 
ResponseStatusExceptionResolver 
DefaultHandlerExceptionResolver 

上面几个Bean实例。这几个类都是用来做什么的呢?

前两个是HandlerMapping接口的实现类,用来处理请求映射的。其中第一个RequestMappingHandlerMapping是处理@RequestMapping注解的。第二个BeanNameUrlHandlerMapping会将controller类的名字映射为请求url。

中间三个是用来处理请求的。具体点说就是确定调用哪个Controller的哪个方法来处理当前请求。第一个RequestMappingHandlerAdapter处理@Controller注解的处理器,支持自定义方法参数和返回值(很酷)。第二个HttpRequestHandlerAdapter是处理继承HttpRequestHandler的处理器。第三个SimpleControllerHandlerAdapter处理继承自Controller接口的处理器。

后面三个
(ExceptionHandlerExceptionResolver ,ResponseStatusExceptionResolver ,
DefaultHandlerExceptionResolver )是用来处理异常的解析器。

实现

光说无凭据,我们直接看代码:

public BeanDefinition parse(Element element, ParserContext parserContext) {  
        Object source = parserContext.extractSource(element);  

        CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(element.getTagName(), source);  
        parserContext.pushContainingComponent(compDefinition);  

        RuntimeBeanReference contentNegotiationManager = getContentNegotiationManager(element, source, parserContext);  
        //第一个在这 RequestMappingHandlerMapping  
        RootBeanDefinition handlerMappingDef = new RootBeanDefinition(RequestMappingHandlerMapping.class);  
        handlerMappingDef.setSource(source);  
        handlerMappingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);  
        handlerMappingDef.getPropertyValues().add("order", 0);  
        handlerMappingDef.getPropertyValues().add("removeSemicolonContent", false);  
        handlerMappingDef.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager);  
        String methodMappingName = parserContext.getReaderContext().registerWithGeneratedName(handlerMappingDef);  
        //第二个在这 RequestMappingHandlerAdapter  
        RootBeanDefinition handlerAdapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);  
        handlerAdapterDef.setSource(source);  
        handlerAdapterDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);  
        handlerAdapterDef.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager);  
        handlerAdapterDef.getPropertyValues().add("webBindingInitializer", bindingDef);  
        handlerAdapterDef.getPropertyValues().add("messageConverters", messageConverters);  
        if (element.hasAttribute("ignoreDefaultModelOnRedirect")) {  
            Boolean ignoreDefaultModel = Boolean.valueOf(element.getAttribute("ignoreDefaultModelOnRedirect"));  
            handlerAdapterDef.getPropertyValues().add("ignoreDefaultModelOnRedirect", ignoreDefaultModel);  
        }  
        if (argumentResolvers != null) {  
            handlerAdapterDef.getPropertyValues().add("customArgumentResolvers", argumentResolvers);  
        }  
        if (returnValueHandlers != null) {  
            handlerAdapterDef.getPropertyValues().add("customReturnValueHandlers", returnValueHandlers);  
        }  
        if (asyncTimeout != null) {  
            handlerAdapterDef.getPropertyValues().add("asyncRequestTimeout", asyncTimeout);  
        }  
        if (asyncExecutor != null) {  
            handlerAdapterDef.getPropertyValues().add("taskExecutor", asyncExecutor);  
        }  
        handlerAdapterDef.getPropertyValues().add("callableInterceptors", callableInterceptors);  
        handlerAdapterDef.getPropertyValues().add("deferredResultInterceptors", deferredResultInterceptors);  
        String handlerAdapterName = parserContext.getReaderContext().registerWithGeneratedName(handlerAdapterDef);  
        //异常处理解析器  
        RootBeanDefinition exceptionHandlerExceptionResolver = new RootBeanDefinition(ExceptionHandlerExceptionResolver.class);  
        exceptionHandlerExceptionResolver.setSource(source);  
        exceptionHandlerExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);  
        exceptionHandlerExceptionResolver.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager);  
        exceptionHandlerExceptionResolver.getPropertyValues().add("messageConverters", messageConverters);  
        exceptionHandlerExceptionResolver.getPropertyValues().add("order", 0);  
        String methodExceptionResolverName =  
                parserContext.getReaderContext().registerWithGeneratedName(exceptionHandlerExceptionResolver);  
        //异常处理解析器  
        RootBeanDefinition responseStatusExceptionResolver = new RootBeanDefinition(ResponseStatusExceptionResolver.class);  
        responseStatusExceptionResolver.setSource(source);  
        responseStatusExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);  
        responseStatusExceptionResolver.getPropertyValues().add("order", 1);  
        String responseStatusExceptionResolverName =  
                parserContext.getReaderContext().registerWithGeneratedName(responseStatusExceptionResolver);  
        //异常处理解析器  
        RootBeanDefinition defaultExceptionResolver = new RootBeanDefinition(DefaultHandlerExceptionResolver.class);  
        defaultExceptionResolver.setSource(source);  
        defaultExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);  
        defaultExceptionResolver.getPropertyValues().add("order", 2);  
        String defaultExceptionResolverName =  
                parserContext.getReaderContext().registerWithGeneratedName(defaultExceptionResolver);  

        parserContext.registerComponent(new BeanComponentDefinition(handlerMappingDef, methodMappingName));  
        parserContext.registerComponent(new BeanComponentDefinition(handlerAdapterDef, handlerAdapterName));  
        parserContext.registerComponent(new BeanComponentDefinition(exceptionHandlerExceptionResolver, methodExceptionResolverName));  
        parserContext.registerComponent(new BeanComponentDefinition(responseStatusExceptionResolver, responseStatusExceptionResolverName));  
        parserContext.registerComponent(new BeanComponentDefinition(defaultExceptionResolver, defaultExceptionResolverName));  
        parserContext.registerComponent(new BeanComponentDefinition(mappedCsInterceptorDef, mappedInterceptorName));  
        //这里注册了BeanNameUrlHandlerMapping,SimpleControllerHandlerAdapter等  
        // Ensure BeanNameUrlHandlerMapping (SPR-8289) and default HandlerAdapters are not "turned off"  
        MvcNamespaceUtils.registerDefaultComponents(parserContext, source);  

        parserContext.popAndRegisterContainingComponent();  

        return null;  
    }  
public static void registerDefaultComponents(ParserContext parserContext, Object source) {  
        registerBeanNameUrlHandlerMapping(parserContext, source);  
        registerHttpRequestHandlerAdapter(parserContext, source);  
        registerSimpleControllerHandlerAdapter(parserContext, source);  
    }  

总结

RequestMappingHandlerMapping/RequestMappingHandlerAdapter。

第一个是HandlerMapping的实现类,它会处理@RequestMapping 注解,并将其注册到请求映射表中。
第二个是HandlerAdapter的实现类,它是处理请求的适配器,说白了,就是确定调用哪个类的哪个方法,并且构造方法参数,返回值

<context:component-scan/>区别

标签是告诉Spring 来扫描指定包下的类,并注册被@Component,@Controller,@Service,@Repository等注解标记的组件。
<mvc:annotation-driven/>是告知Spring,我们启用注解驱动。然后Spring会自动为我们注册上面说到的几个Bean到工厂中,来处理我们的请求。

<context:annotation-config/>的区别

当我们需要使用注解模式时,直接在Spring配置文件中定义这些Bean显得比较笨拙,例如:
使用@Autowired注解,必须事先在Spring容器中声明AutowiredAnnotationBeanPostProcessor的Bean

<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor "/>

使用 @Required注解,就必须声明RequiredAnnotationBeanPostProcessor的Bean

<bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor"/>  

简单的说,用什么注解,就需要声明对应的BeanPostProcessor。这样的声明未免太不优雅,而Spring为我们提供了一种极为方便注册这些BeanPostProcessor的方式,即使用<context:annotation- config/>隐式地向 Spring容器注册AutowiredAnnotationBeanPostProcessor RequiredAnnotationBeanPostProcessor
以及PersistenceAnnotationBeanPostProcessor
这4个BeanPostProcessor。
  另外,在我们使用注解时一般都会配置扫描包路径选项,即<context:component-scan/>。该配置项其实也包含了自动注入上述processor的功能,因此当使用<context:component-scan/>后,即可将<context:annotation-config/>省去,但必须要配置全!以防万一,还是同时声明的好。

参考:
https://my.oschina.net/HeliosFly/blog/205343
http://www.cnblogs.com/yangzhilong/p/3725849.html

猜你喜欢

转载自blog.csdn.net/mccand1234/article/details/76793980