SpringMVC
来源:互联网 发布:沙河网络服装批发市场 编辑:程序博客网 时间:2024/06/10 21:51
【1】AnnotationDrivenBeanDefinitionParser
通常如果我们希望通过注解的方式来进行Spring MVC开发,我们都会在***-servlet.xml
中加入<mvc:annotation-driven/>
标签来告诉Spring我们的目的。
但是我们为什么这么做呢?这个标签是什么意思呢?它做了什么呢?
同样为了弄清楚这些问题, 像<context:component-scan/>
标签一样,我们先找到它的解析类。前面说过了,所有的自定义命名空间(像mvc,context等)下的标签解析都是由BeanDefinitionParser接口的子类来完成的。
查看BeanDefinitionParser说明:
该接口被默认bean定义文档阅读者使用以处理自定义和顶级(直属<beans/>
)标签。
实现者可以自由地将标签里面的元数据转化成许多需要的BeanDefinition。
解析器从标签隶属的namespace对应的NamespaceHandler找到合适的BeanDefinitonParser,
该解析器的实现类有:
我们看到有多个AnnotationDrivenBeanDefinitionParser,他们是用来处理不同命名空间下的标签的,我们今天研究<annotation-driven/>
的是<mvc:annotation-driven/>
标签,所以我们找到对应的实现类是org.springframework.web.servlet.config.AnnotationDrivenBeanDefinitionParser。
AnnotationDrivenBeanDefinitionParser的文档说明如下:
* A {@link BeanDefinitionParser} that provides the configuration for the * {@code <annotation-driven/>} MVC namespace element. * * <p>This class registers the following {@link HandlerMapping}s:</p> * <ul> * <li>{@link RequestMappingHandlerMapping} * ordered at 0 for mapping requests to annotated controller methods. * <li>{@link BeanNameUrlHandlerMapping} * ordered at 2 to map URL paths to controller bean names. * </ul> * * <p><strong>Note:</strong> Additional HandlerMappings may be registered * as a result of using the {@code <view-controller>} or the * {@code <resources>} MVC namespace elements. * * <p>This class registers the following {@link HandlerAdapter}s: * <ul> * <li>{@link RequestMappingHandlerAdapter} * for processing requests with annotated controller methods. * <li>{@link HttpRequestHandlerAdapter} * for processing requests with {@link HttpRequestHandler}s. * <li>{@link SimpleControllerHandlerAdapter} * for processing requests with interface-based {@link Controller}s. * </ul> * * <p>This class registers the following {@link HandlerExceptionResolver}s: * <ul> * <li>{@link ExceptionHandlerExceptionResolver} for handling exceptions * through @{@link ExceptionHandler} methods. * <li>{@link ResponseStatusExceptionResolver} for exceptions annotated * with @{@link ResponseStatus}. * <li>{@link DefaultHandlerExceptionResolver} for resolving known Spring * exception types * </ul> * * <p>This class registers an {@link org.springframework.util.AntPathMatcher} * and a {@link org.springframework.web.util.UrlPathHelper} to be used by: * <ul> * <li>the {@link RequestMappingHandlerMapping}, * <li>the {@link HandlerMapping} for ViewControllers * <li>and the {@link HandlerMapping} for serving resources * </ul> * Note that those beans can be configured by using the {@code path-matching} MVC namespace element. * * <p>Both the {@link RequestMappingHandlerAdapter} and the * {@link ExceptionHandlerExceptionResolver} are configured with instances of * the following by default: * <ul> * <li>A {@link ContentNegotiationManager} * <li>A {@link DefaultFormattingConversionService} * <li>A {@link org.springframework.validation.beanvalidation.LocalValidatorFactoryBean} * if a JSR-303 implementation is available on the classpath * <li>A range of {@link HttpMessageConverter}s depending on what 3rd party * libraries are available on the classpath. * </ul> * * @author Keith Donald * @author Juergen Hoeller * @author Arjen Poutsma * @author Rossen Stoyanchev * @author Brian Clozel * @author Agim Emruli * @since 3.0
该注释文档说明该解析器想容器中注入了如下类:
RequestMappingHandlerMapping
BeanNameUrlHandlerMapping
RequestMappingHandlerAdapter
HttpRequestHandlerAdapter
SimpleControllerHandlerAdapter
ExceptionHandlerExceptionResolver
ResponseStatusExceptionResolver
DefaultHandlerExceptionResolver
上面几个Bean实例。这几个类都是用来做什么的呢?
前两个是HandlerMapping接口的实现类,用来处理请求映射的。
其中第一个是处理@RequestMapping注解的。.
第二个会将controller类的名字映射为请求url。
中间三个是用来处理请求的。具体点说就是确定调用哪个controller的哪个方法来处理当前请求。
第一个处理@Controller注解的处理器,支持自定义方法参数和返回值(很酷)。
第二个是处理继承HttpRequestHandler的处理器。
第三个处理继承自Controller接口的处理器。
后面三个是用来处理异常的解析器。
【2】代码追溯
public BeanDefinition parse(Element element, ParserContext parserContext) { Object source = parserContext.extractSource(element); XmlReaderContext readerContext = parserContext.getReaderContext(); CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(element.getTagName(), source); parserContext.pushContainingComponent(compDefinition); RuntimeBeanReference contentNegotiationManager = getContentNegotiationManager(element, source, parserContext);/* RequestMappingHandlerMapping order:0*/ RootBeanDefinition handlerMappingDef = new RootBeanDefinition(RequestMappingHandlerMapping.class); handlerMappingDef.setSource(source); handlerMappingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); handlerMappingDef.getPropertyValues().add("order", 0); handlerMappingDef.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager); if (element.hasAttribute("enable-matrix-variables")) { Boolean enableMatrixVariables = Boolean.valueOf(element.getAttribute("enable-matrix-variables")); handlerMappingDef.getPropertyValues().add("removeSemicolonContent", !enableMatrixVariables); } else if (element.hasAttribute("enableMatrixVariables")) { Boolean enableMatrixVariables = Boolean.valueOf(element.getAttribute("enableMatrixVariables")); handlerMappingDef.getPropertyValues().add("removeSemicolonContent", !enableMatrixVariables); } configurePathMatchingProperties(handlerMappingDef, element, parserContext); readerContext.getRegistry().registerBeanDefinition(HANDLER_MAPPING_BEAN_NAME , handlerMappingDef); RuntimeBeanReference corsConfigurationsRef = MvcNamespaceUtils.registerCorsConfigurations(null, parserContext, source); handlerMappingDef.getPropertyValues().add("corsConfigurations", corsConfigurationsRef); RuntimeBeanReference conversionService = getConversionService(element, source, parserContext); RuntimeBeanReference validator = getValidator(element, source, parserContext); RuntimeBeanReference messageCodesResolver = getMessageCodesResolver(element); RootBeanDefinition bindingDef = new RootBeanDefinition(ConfigurableWebBindingInitializer.class); bindingDef.setSource(source); bindingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); bindingDef.getPropertyValues().add("conversionService", conversionService); bindingDef.getPropertyValues().add("validator", validator); bindingDef.getPropertyValues().add("messageCodesResolver", messageCodesResolver); ManagedList<?> messageConverters = getMessageConverters(element, source, parserContext); ManagedList<?> argumentResolvers = getArgumentResolvers(element, parserContext); ManagedList<?> returnValueHandlers = getReturnValueHandlers(element, parserContext); String asyncTimeout = getAsyncTimeout(element); RuntimeBeanReference asyncExecutor = getAsyncExecutor(element); ManagedList<?> callableInterceptors = getCallableInterceptors(element, source, parserContext); ManagedList<?> deferredResultInterceptors = getDeferredResultInterceptors(element, source, parserContext);/* 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); addRequestBodyAdvice(handlerAdapterDef); addResponseBodyAdvice(handlerAdapterDef); if (element.hasAttribute("ignore-default-model-on-redirect")) { Boolean ignoreDefaultModel = Boolean.valueOf(element.getAttribute("ignore-default-model-on-redirect")); handlerAdapterDef.getPropertyValues().add("ignoreDefaultModelOnRedirect", ignoreDefaultModel); } else if (element.hasAttribute("ignoreDefaultModelOnRedirect")) { // "ignoreDefaultModelOnRedirect" spelling is deprecated 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); readerContext.getRegistry().registerBeanDefinition(HANDLER_ADAPTER_BEAN_NAME , handlerAdapterDef); String uriCompContribName = MvcUriComponentsBuilder.MVC_URI_COMPONENTS_CONTRIBUTOR_BEAN_NAME; RootBeanDefinition uriCompContribDef = new RootBeanDefinition(CompositeUriComponentsContributorFactoryBean.class); uriCompContribDef.setSource(source); uriCompContribDef.getPropertyValues().addPropertyValue("handlerAdapter", handlerAdapterDef); uriCompContribDef.getPropertyValues().addPropertyValue("conversionService", conversionService); readerContext.getRegistry().registerBeanDefinition(uriCompContribName, uriCompContribDef); RootBeanDefinition csInterceptorDef = new RootBeanDefinition(ConversionServiceExposingInterceptor.class); csInterceptorDef.setSource(source); csInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, conversionService); RootBeanDefinition mappedCsInterceptorDef = new RootBeanDefinition(MappedInterceptor.class); mappedCsInterceptorDef.setSource(source); mappedCsInterceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); mappedCsInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, (Object) null); mappedCsInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(1, csInterceptorDef); String mappedInterceptorName = readerContext.registerWithGeneratedName(mappedCsInterceptorDef);/* ExceptionHandlerExceptionResolver */ 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); addResponseBodyAdvice(exceptionHandlerExceptionResolver); if (argumentResolvers != null) { exceptionHandlerExceptionResolver.getPropertyValues().add("customArgumentResolvers", argumentResolvers); } if (returnValueHandlers != null) { exceptionHandlerExceptionResolver.getPropertyValues().add("customReturnValueHandlers", returnValueHandlers); } String methodExceptionResolverName = readerContext.registerWithGeneratedName(exceptionHandlerExceptionResolver);/* ResponseStatusExceptionResolver */ RootBeanDefinition responseStatusExceptionResolver = new RootBeanDefinition(ResponseStatusExceptionResolver.class); responseStatusExceptionResolver.setSource(source); responseStatusExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); responseStatusExceptionResolver.getPropertyValues().add("order", 1); String responseStatusExceptionResolverName = readerContext.registerWithGeneratedName(responseStatusExceptionResolver);/* DefaultHandlerExceptionResolver */ RootBeanDefinition defaultExceptionResolver = new RootBeanDefinition(DefaultHandlerExceptionResolver.class); defaultExceptionResolver.setSource(source); defaultExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); defaultExceptionResolver.getPropertyValues().add("order", 2); String defaultExceptionResolverName = readerContext.registerWithGeneratedName(defaultExceptionResolver); parserContext.registerComponent(new BeanComponentDefinition(handlerMappingDef, HANDLER_MAPPING_BEAN_NAME)); parserContext.registerComponent(new BeanComponentDefinition(handlerAdapterDef, HANDLER_ADAPTER_BEAN_NAME)); parserContext.registerComponent(new BeanComponentDefinition(uriCompContribDef, uriCompContribName)); 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 HttpRequestHandlerAdapter 和 SimpleControllerHandlerAdapter*/ // Ensure BeanNameUrlHandlerMapping (SPR-8289) and default HandlerAdapters are not "turned off" MvcNamespaceUtils.registerDefaultComponents(parserContext, source); parserContext.popAndRegisterContainingComponent(); return null; }
注册默认mapping和adapter方法如下:
public static void registerDefaultComponents(ParserContext parserContext, Object source) { registerBeanNameUrlHandlerMapping(parserContext, source); registerHttpRequestHandlerAdapter(parserContext, source); registerSimpleControllerHandlerAdapter(parserContext, source); }
【3】总结
我们知道了它们自动为我们注册了这么多的Bean,那这些Bean是做什么的呢?
主要说明里面的两个,RequestMappingHandlerMapping和RequestMappingHandlerAdapter。
第一个是HandlerMapping的实现类,它会处理@RequestMapping 注解,并将其注册到请求映射表中。
第二个是HandlerAdapter的实现类,它是处理请求的适配器,说白了,就是确定调用哪个类的哪个方法,并且构造方法参数,返回值。
那么它跟<context:component-scan/>
有什么区别呢?
其实<context:component-scan/>
标签是告诉Spring 来扫描指定包下的类,并注册被@Component,@Controller,@Service,@Repository等注解标记的组件(即,项目启动完成前,这些被注解的组件就会被实例化bean放入容器上下文中)。
而<mvc:annotation-driven/>
是告知Spring,我们启用注解驱动,为WEB 应用服务(我们就可以使用该标签注册的几个bean的功能)。然后Spring会自动为我们注册上面说到的几个Bean到工厂中,来处理我们的请求。
即,如果不想手动配置bean(xml),使用注解获取bean,就必须使用<context:component-scan/>
。
如果想使web项目正常运转,一般情况下,<mvc:annotation-driven/>
是必需的!
项目中二者相辅相成,缺一不可!!!
- SpringMVC
- springmvc
- SpringMVC
- SpringMVC
- springMvc
- springMVC
- springmvc
- springMVC
- springMVC
- springmvc
- SpringMVC
- SpringMVC
- springMvc
- springmvc
- springmvc
- SpringMVC
- Springmvc
- springmvc
- XGBoost+LR融合方案
- JS页面跳转代码
- nodejs 5 nodejs的web应用-http服务器(http, 路由,get,post,https)
- View inflate 方法与 LayoutInflater inflate 方法的区别详解
- 抽象工厂模式
- SpringMVC
- 关于 quartz 1.6.1 的一个死等问题,导致任务不执行
- Codeforces Round #286 div.2 D 505D. Mr. Kitayuta's Technology【强连通分量,弱联通分量】
- Linux命令之awk
- 使用Axis2生成soap客户端
- get_maincat()分类调用方法
- Nginx服务器安装,高性能的HTTP、TCP、反向代理、负载均衡等服务和配置
- 文章标题
- SWAT—Samba WEB管理工具