编程技术分享平台

网站首页 > 技术教程 正文

annotation-driven和component-scan 源码以及详细分析

xnh888 2024-10-19 15:59:16 技术教程 14 ℃ 0 评论

<context:component-scan />和<mvc:annotation-driven>完全实现不同的目的。

<context:component-scan /> 如名字表示的意思一样,用于组件扫描。默认扫描 @Component 注解的组件(或者子注解,如 @Controller、@Service等等)。它仅仅注册这些类的实例到 application context中,作为beans。

<mvc:annotation-driven />用来启动Spring MVC,并注册 RequestMappingHandlerMapping和RequestMappingHandlerAdapter,和其他一些beans。第一个用来连接请求到特定方法(在@Controller 注解类中的 @RequestMapping 注解方法)。最后一个知道如何执行 @RequestMapping 注解的方法。

如果在aplication context 中没有beans,<mvc:annotation-driven /> 不负责扫描或检测 @Controllers,这样就无法处理 request mappings。现在,有几种方法注册这些beans 到application context 中,其中之一就是前面提及的 <context:component-scan />。

一般而言,如果一个 @Controller 没有 <mvc:annotation-driven />配置,就没有任何用处了(除了占用内存而已)。它就无法绑定到进入的请求,仅仅在application context 中挂着。它就像其他的beans一样,没有什么特殊的地方。

(最近,过期版本的Spring 注册了DefaultAnnotationHandlerMapping bean,它负责处理 @Controller,但是已经过期了。)


从IoC容器中查找相应的配置,如果查找不到,就使用DispatcherServlet.properties 默认配置并把配置的类型加入到 IoC 中作为Bean。

如下是 DispatcherServlet.properties 文件内容:

# Default implementation classes for DispatcherServlet's strategy interfaces.

# Used as fallback when no matching beans are found in the DispatcherServlet context.

# Not meant to be customized by application developers.

DispatcherServlet的策略接口的默认实现类。

当在DispatcherServlet 上下文中没有找到匹配的beans,则当做备份beans来使用。

annotation-driven用于打开注解驱动。

一般根据前缀来注册相关的注解类:

<tx:annotation-driven/>:支持事务注解的(@Transactional)。

<mvc:annotation-driven/>:支持MVC注解。


component-scan 和 annotation-driven 源码解析

  • component-scan:扫描指定包下被@Component,@Service,@Controller,@Repository,@Configuration注解所标注的class。实际上,都是通过@Component来完成的。
  • annotation-driven:注册Spring MVC的web组件,并完成HandlerMethod的解析。

context:component-scan标签由ContextNamespaceHandler处理器处理。

mvc:annotation-driven标签由MvcNamespaceHandler处理器处理。

ContextNamespaceHandler 处理器源码:

public class ContextNamespaceHandler extends NamespaceHandlerSupport {

@Override

public void init() {

registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());

registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());

registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());

registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());

registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());

registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());

registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());

registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());

}

由此可见,component-scan是由具体的ComponentScanBeanDefinitionParser解析器解析,它实现了BeanDefinitionParser接口,完成扫描指定包路径下的class文件,并注册所有满足条件的BeanDefinition。

MvcNamespaceHandler 处理器源码:

public class MvcNamespaceHandler extends NamespaceHandlerSupport {

@Override

public void init() {

registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());

registerBeanDefinitionParser("default-servlet-handler", new DefaultServletHandlerBeanDefinitionParser());

registerBeanDefinitionParser("interceptors", new InterceptorsBeanDefinitionParser());

registerBeanDefinitionParser("resources", new ResourcesBeanDefinitionParser());

registerBeanDefinitionParser("view-controller", new ViewControllerBeanDefinitionParser());

registerBeanDefinitionParser("redirect-view-controller", new ViewControllerBeanDefinitionParser());

registerBeanDefinitionParser("status-controller", new ViewControllerBeanDefinitionParser());

registerBeanDefinitionParser("view-resolvers", new ViewResolversBeanDefinitionParser());

registerBeanDefinitionParser("tiles-configurer", new TilesConfigurerBeanDefinitionParser());

registerBeanDefinitionParser("freemarker-configurer", new FreeMarkerConfigurerBeanDefinitionParser());

registerBeanDefinitionParser("groovy-configurer", new GroovyMarkupConfigurerBeanDefinitionParser());

registerBeanDefinitionParser("script-template-configurer", new ScriptTemplateConfigurerBeanDefinitionParser());

registerBeanDefinitionParser("cors", new CorsBeanDefinitionParser());

}

AnnotationDrivenBeanDefinitionParser.parse()方法很长:

...

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(exceptionResolver, methodExceptionResolverName));

parserContext.registerComponent(new BeanComponentDefinition(statusExceptionResolver, statusExResolverName));

parserContext.registerComponent(new BeanComponentDefinition(defaultExceptionResolver, defaultExResolverName));

parserContext.registerComponent(new BeanComponentDefinition(mappedCsInterceptorDef, mappedInterceptorName));

...

mvc:annotation-driven解析器,向Spring IOC容器注册了很多SpringMVC的web组件,我们重点关注下面几个组件,其余读者可自行了解:

1、RequestMappingHandlerMapping:负责解析HandlerMethod,并根据request请求返回HandlerExecutionChain,HandlerExecutionChain是HandlerMethod和方法拦截器的合体。

2、RequestMappingHandlerAdapter:负责处理request请求,并返回ModelAndView对象。

3、DefaultFormattingConversionService:类型转换服务类,如String to Date,Date to String。

4、HttpMessageConverter:消息转换器,如根据HTTP的MIME类型,JavaBean to Json,JavaBean to XML。

5、ConfigurableWebBindingInitializer:WebDataBinder的初始化器。

...

其余可自行查看。

context:component-scan:主要完成bean的解析工作。

mvc:annotation-driven:主要完成从controllor bean中解析出RequestMappingInfo,封装为HandlerMethod对象。

Spring MVC 解读——<mvc:annotation-driven/>

如下是resources/applicationContext.xml 配置文件中,<context:component-scan /> 的使用,配置扫描com.rickie package以及sub-package。

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表