1.フロンティア
Spring MVCプロジェクトでは、構成<mvc:annotation-driven>を使用することがよくありますが、この構成は正確に何をしますか?以下で分析してみましょう。最初に、次の図に示すように、mvcの名前空間の定義を見つけます。
上の図からわかるように、アノテーション駆動型構成の実装クラスは、MvcNamespaceHandlerクラスで定義する必要があります。そうではありませんか?MvcNamespaceHandlerのソースコードを見てみましょう
二、MvcNamespaceHandler
MvcNamespaceHandlerのソースコードは次のとおりです。
/**
* {@link NamespaceHandler} for Spring MVC configuration namespace.
*
* @author Keith Donald
* @author Jeremy Grelle
* @author Sebastien Deleuze
* @since 3.0
*/
public class MvcNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
// 注册 annotation-driven 标签的解析器 AnnotationDrivenBeanDefinitionParser,用来解析 Controller
registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
// 注册 default-servlet-handler 标签的解析器 DefaultServletHandlerBeanDefinitionParser,用来解析静态资源文件(html、jsp、js和css等)
registerBeanDefinitionParser("default-servlet-handler", new DefaultServletHandlerBeanDefinitionParser());
// 注册 interceptors 标签的解析器 InterceptorsBeanDefinitionParser,用来解析拦截器
registerBeanDefinitionParser("interceptors", new InterceptorsBeanDefinitionParser());
// 注册 resources 标签的解析器 ResourcesBeanDefinitionParser,用来解析资源文件
registerBeanDefinitionParser("resources", new ResourcesBeanDefinitionParser());
// 注册 view-controller、redirect-view-controller、status-controller 标签的解析器 ViewControllerBeanDefinitionParser,用来解析视图view
registerBeanDefinitionParser("view-controller", new ViewControllerBeanDefinitionParser());
registerBeanDefinitionParser("redirect-view-controller", new ViewControllerBeanDefinitionParser());
registerBeanDefinitionParser("status-controller", new ViewControllerBeanDefinitionParser());
// 注册 view-resolvers 标签的解析器 ViewResolversBeanDefinitionParser,用来解析视图解析器
registerBeanDefinitionParser("view-resolvers", new ViewResolversBeanDefinitionParser());
registerBeanDefinitionParser("tiles-configurer", new TilesConfigurerBeanDefinitionParser());
// 注册 freemarker-configurer 标签的解析器 FreeMarkerConfigurerBeanDefinitionParser,用来解析 freemarker 配置
registerBeanDefinitionParser("freemarker-configurer", new FreeMarkerConfigurerBeanDefinitionParser());
// 注册 groovy-configurer 标签的解析器 GroovyMarkupConfigurerBeanDefinitionParser,用来解析 groovy 配置
registerBeanDefinitionParser("groovy-configurer", new GroovyMarkupConfigurerBeanDefinitionParser());
// 注册 script-template-configurer 标签的解析器 ScriptTemplateConfigurerBeanDefinitionParser,用来解析 script 脚本模板配置
registerBeanDefinitionParser("script-template-configurer", new ScriptTemplateConfigurerBeanDefinitionParser());
// 注册 cors 标签的解析器 CorsBeanDefinitionParser,用来解析跨域
registerBeanDefinitionParser("cors", new CorsBeanDefinitionParser());
}
}
上記のソースコードから、アノテーション駆動型構成に対応する分析クラスAnnotationDrivenBeanDefinitionParserがMvcNamespaceHandlerのinitメソッドで実際に定義されていることがわかります。次に、アノテーション駆動型構成によって実装される特定のビジネスは、AnnotationDrivenBeanDefinitionParserクラスに含まれている必要があります。 AnnotationDrivenBeanDefinitionParserソースを分析します
三、AnnotationDrivenBeanDefinitionParser
AnnotationDrivenBeanDefinitionParserのparseメソッドは、特定の解析ロジックを実装します。ソースコードは次のとおりです。
/**
* A {@link BeanDefinitionParser} that provides the configuration for the
* {@code <annotation-driven/>} MVC namespace element.
*
* <p>This class registers the following {@link HandlerMapping HandlerMappings}:</p>
* <ul>
* <li>{@link RequestMappingHandlerMapping}
* 将请求映射到带注解的控制器方法时,按照0排序,例如 @RequestMapping("/test")
* ordered at 0 for mapping requests to annotated controller methods.
* <li>{@link BeanNameUrlHandlerMapping}
* 将URL路径映射到控制器bean名称时,按照2排序
* 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 HandlerAdapters}:
* <ul>
* <li>{@link RequestMappingHandlerAdapter}
* 处理带有@controller注解的适配器(支持自定义的参数和返回值),对应于 RequestMappingHandlerMapping,例如 @RequestMapping("/test")
* for processing requests with annotated controller methods.
* <li>{@link HttpRequestHandlerAdapter}
* 处理带有 HttpRequestHandlers 的适配器
* for processing requests with {@link HttpRequestHandler HttpRequestHandlers}.
* <li>{@link SimpleControllerHandlerAdapter}
* 处理基于 Controllers 接口的适配器
* for processing requests with interface-based {@link Controller Controllers}.
* </ul>
*
* 异常处理器
* <p>This class registers the following {@link HandlerExceptionResolver HandlerExceptionResolvers}:
* <ul>
* <li>{@link ExceptionHandlerExceptionResolver} for handling exceptions through
* {@link org.springframework.web.bind.annotation.ExceptionHandler} methods.
* <li>{@link ResponseStatusExceptionResolver} for exceptions annotated
* with {@link org.springframework.web.bind.annotation.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 HttpMessageConverters} depending on which third-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
*/
class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext context) {
Object source = context.extractSource(element);
XmlReaderContext readerContext = context.getReaderContext();
CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(element.getTagName(), source);
context.pushContainingComponent(compDefinition);
RuntimeBeanReference contentNegotiationManager = getContentNegotiationManager(element, source, context);
// 定义 RequestMappingHandlerMapping
RootBeanDefinition handlerMappingDef = new RootBeanDefinition(RequestMappingHandlerMapping.class);
handlerMappingDef.setSource(source);
handlerMappingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
// 排序值为 0
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);
}
configurePathMatchingProperties(handlerMappingDef, element, context);
// 注册 RequestMappingHandlerMapping 类型对应的 RootBeanDefinition
readerContext.getRegistry().registerBeanDefinition(HANDLER_MAPPING_BEAN_NAME, handlerMappingDef);
RuntimeBeanReference corsRef = MvcNamespaceUtils.registerCorsConfigurations(null, context, source);
handlerMappingDef.getPropertyValues().add("corsConfigurations", corsRef);
RuntimeBeanReference conversionService = getConversionService(element, source, context);
RuntimeBeanReference validator = getValidator(element, source, context);
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, context);
ManagedList<?> argumentResolvers = getArgumentResolvers(element, context);
ManagedList<?> returnValueHandlers = getReturnValueHandlers(element, context);
String asyncTimeout = getAsyncTimeout(element);
RuntimeBeanReference asyncExecutor = getAsyncExecutor(element);
ManagedList<?> callableInterceptors = getCallableInterceptors(element, source, context);
ManagedList<?> deferredResultInterceptors = getDeferredResultInterceptors(element, source, context);
// 定义 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);
}
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);
// 注册 RequestMappingHandlerAdapter 对应的 RootBeanDefinition
readerContext.getRegistry().registerBeanDefinition(HANDLER_ADAPTER_BEAN_NAME, handlerAdapterDef);
RootBeanDefinition uriContributorDef =
new RootBeanDefinition(CompositeUriComponentsContributorFactoryBean.class);
uriContributorDef.setSource(source);
uriContributorDef.getPropertyValues().addPropertyValue("handlerAdapter", handlerAdapterDef);
uriContributorDef.getPropertyValues().addPropertyValue("conversionService", conversionService);
String uriContributorName = MvcUriComponentsBuilder.MVC_URI_COMPONENTS_CONTRIBUTOR_BEAN_NAME;
readerContext.getRegistry().registerBeanDefinition(uriContributorName, uriContributorDef);
RootBeanDefinition csInterceptorDef = new RootBeanDefinition(ConversionServiceExposingInterceptor.class);
csInterceptorDef.setSource(source);
csInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, conversionService);
RootBeanDefinition mappedInterceptorDef = new RootBeanDefinition(MappedInterceptor.class);
mappedInterceptorDef.setSource(source);
mappedInterceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
mappedInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, (Object) null);
mappedInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(1, csInterceptorDef);
String mappedInterceptorName = readerContext.registerWithGeneratedName(mappedInterceptorDef);
// 定义 ExceptionHandlerExceptionResolver 异常处理器
RootBeanDefinition methodExceptionResolver = new RootBeanDefinition(ExceptionHandlerExceptionResolver.class);
methodExceptionResolver.setSource(source);
methodExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
methodExceptionResolver.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager);
methodExceptionResolver.getPropertyValues().add("messageConverters", messageConverters);
// 排序值为 0
methodExceptionResolver.getPropertyValues().add("order", 0);
addResponseBodyAdvice(methodExceptionResolver);
if (argumentResolvers != null) {
methodExceptionResolver.getPropertyValues().add("customArgumentResolvers", argumentResolvers);
}
if (returnValueHandlers != null) {
methodExceptionResolver.getPropertyValues().add("customReturnValueHandlers", returnValueHandlers);
}
String methodExResolverName = readerContext.registerWithGeneratedName(methodExceptionResolver);
// 定义 ResponseStatusExceptionResolver 返回状态异常解析器
RootBeanDefinition statusExceptionResolver = new RootBeanDefinition(ResponseStatusExceptionResolver.class);
statusExceptionResolver.setSource(source);
statusExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
// 排序值为 1
statusExceptionResolver.getPropertyValues().add("order", 1);
String statusExResolverName = readerContext.registerWithGeneratedName(statusExceptionResolver);
// 定义Spring中已知的异常解析器
RootBeanDefinition defaultExceptionResolver = new RootBeanDefinition(DefaultHandlerExceptionResolver.class);
defaultExceptionResolver.setSource(source);
defaultExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
// 排序值为 2
defaultExceptionResolver.getPropertyValues().add("order", 2);
String defaultExResolverName = readerContext.registerWithGeneratedName(defaultExceptionResolver);
// 将上面所有的 bean 组件注册到上下文中
context.registerComponent(new BeanComponentDefinition(handlerMappingDef, HANDLER_MAPPING_BEAN_NAME));
context.registerComponent(new BeanComponentDefinition(handlerAdapterDef, HANDLER_ADAPTER_BEAN_NAME));
context.registerComponent(new BeanComponentDefinition(uriContributorDef, uriContributorName));
context.registerComponent(new BeanComponentDefinition(mappedInterceptorDef, mappedInterceptorName));
context.registerComponent(new BeanComponentDefinition(methodExceptionResolver, methodExResolverName));
context.registerComponent(new BeanComponentDefinition(statusExceptionResolver, statusExResolverName));
context.registerComponent(new BeanComponentDefinition(defaultExceptionResolver, defaultExResolverName));
// Ensure BeanNameUrlHandlerMapping (SPR-8289) and default HandlerAdapters are not "turned off"
// 注册默认的一些组件,例如 BeanNameUrlHandlerMapping、HttpRequestHandlerAdapter、
// SimpleControllerHandlerAdapter 和 HandlerMappingIntrospector
MvcNamespaceUtils.registerDefaultComponents(context, source);
context.popAndRegisterContainingComponent();
return null;
}
}
上記のソースコードからわかるように、AnnotationDrivenBeanDefinitionParserは、主に多くのBeanを登録する機能を実現します。その中で、RequestMappingHandlerMappingとRequestMappingHandlerAdapterの2つのクラスについて最も懸念しているのは、次の図です。
RequestMappingHandlerMapping:@RequestMappingアノテーションを処理し、それをマッピングテーブル、つまりURLに対応するコントローラーのメソッドに登録するHandlerMappingの実装クラス。
RequestMappingHandlerAdapter:HandlerAdapterの実装クラス。リクエストを処理するのはアダプターであり、どのコントローラーのどのメソッドを呼び出すかを決定します。
この時点で、AnnotationDrivenBeanDefinitionParserのソースコードが分析されました。複雑なロジックはそれほど多くなく、コードコメントが明確に記述されています。
4つのアノテーション主導の役割
AnnotationDrivenBeanDefinitionParserのソースコードを読むと、アノテーション駆動型構成の機能が次のようになっていることがわかります。
1)、主にRequestMappingHandlerMappingおよびRequestMappingHandlerAdapter Beanを登録し、リクエストURLとControllerメソッド間のマッピング関係を保存します
2)、登録された例外ハンドラ
五数要約
<mvc:annotation-driven>がSpring MVCで構成されている場合、すべてのコントローラーが解析されるため、対応する.do要求はコントローラーによって処理されるため、この構成は非常に重要です。リクエストが処理クラスと一致しない場合(<mvc:annotation-driven>の構成がない場合や静的リソースファイルへのアクセスがない場合)、<mvc:default-servlet-handler>の構成(静的リソースファイルの処理)が検索されます。 )DefaultServletHttpRequestHandlerはデフォルトのプロセッサによって処理されます