<context:component-scan/>和<mvc:annotation-driven/>的区别

<mvc:annotation-driven/>相当于注册了DefaultAnnotationHandlerMapping和AnnotationMethodHandlerAdapter两个bean,配置一些messageconverter。即解决了@Controller注解的使用前提配置。 

<context:annotation-config/>是对包进行扫描,实现注释驱动Bean定义,同时将bean自动注入容器中使用。即解决了@Controller标识的类的bean的注入和使用。 

一开始我在写配置的时候,只写了<context:component-scan/>,并没有使用<mvc:annotation-driven/>,servlet拦截*.do,.do请求可以被正确捕捉和处理。代码如下 
mvc-servlet.xml 

Java代码  复制代码  收藏代码
  1. <context:component-scan base-package="com"></context:component-scan>  
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <context:component-scan base-package="com"></context:component-scan>  



web.xml 

Java代码  复制代码  收藏代码
  1. <servlet>   
  2.     <servlet-name>mvc</servlet-name>   
  3.     <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>   
  4.     <load-on-startup>1</load-on-startup>   
  5. </servlet>   
  6. <servlet-mapping>   
  7.     <servlet-name>mvc</servlet-name>   
  8.     <url-pattern>*.do</url-pattern>   
  9. </servlet-mapping>  
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <servlet>  
  2.     <servlet-name>mvc</servlet-name>  
  3.     <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>  
  4.     <load-on-startup>1</load-on-startup>  
  5. </servlet>  
  6. <servlet-mapping>  
  7.     <servlet-name>mvc</servlet-name>  
  8.     <url-pattern>*.do</url-pattern>  
  9. </servlet-mapping>  




后来为了解决静态资源访问的问题,servlet改成了拦截所有请求,即/,并添加了默认的servlet,这时候*.do请求不能被控制器捕捉了,页面错误为404。直到添加了<mvc:annotation-driven/>之后,.do请求才又能被正确捕捉和处理。代码如下 
mvc-servlet.xml 

Java代码  复制代码  收藏代码
  1. <context:component-scan base-package="com"></context:component-scan>   
  2. <mvc:annotation-driven/>   
  3. <mvc:resources mapping="/styles/**" location="/WEB-INF/resource/styles/"/>   
  4. <mvc:default-servlet-handler/>  
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <context:component-scan base-package="com"></context:component-scan>  
  2. <mvc:annotation-driven/>  
  3. <mvc:resources mapping="/styles/**" location="/WEB-INF/resource/styles/"/>  
  4. <mvc:default-servlet-handler/>  



web.xml 

Java代码  复制代码  收藏代码
  1. <servlet>   
  2.     <servlet-name>mvc</servlet-name>   
  3.     <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>   
  4.     <load-on-startup>1</load-on-startup>   
  5. </servlet>   
  6. <servlet-mapping>   
  7.     <servlet-name>mvc</servlet-name>   
  8.     <url-pattern>/</url-pattern>   
  9. </servlet-mapping>  
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <servlet>  
  2.     <servlet-name>mvc</servlet-name>  
  3.     <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>  
  4.     <load-on-startup>1</load-on-startup>  
  5. </servlet>  
  6. <servlet-mapping>  
  7.     <servlet-name>mvc</servlet-name>  
  8.     <url-pattern>/</url-pattern>  
  9. </servlet-mapping>  



是什么原因造成这种区别的呢?为什么一开始没用<mvc:annotation-driven/>的时候可以,添加了默认servlet之后就不行了呢?

 

最后的配置如果没有<mvc:annotation-driven/>,那么所有的Controller可能就没有解析,所有当有请求时候都没有匹配的处理请求类,就都去<mvc:default-servlet-handler/>即default servlet处理了。添加上<mvc:annotation-driven/>后,相应的do请求被Controller处理,而静态资源因为没有相应的Controller就会被default servlet处理。总之没有相应的Controller就会被default servlet处理就ok了。

 

=====http://www.cnblogs.com/shines77/p/3315445.html

mvc:annotation-driven是一种简写的配置方式,那么mvc:annotation-driven到底做了哪些工作呢?如何替换掉mvc:annotation-driven呢?

<mvc:annotation- driven/>在初始化的时候会自动创建两个对 象,org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter 和 org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter, 我们如果想不使用<mvc:annotation-driven/>这种简写方式,将其替换掉的话,就必须自己手动去配置这两个bean对 象。下面是这两个对象的配置方法,和详细的注视说明。

 

==========http://jinnianshilongnian.iteye.com/blog/1762632

context:component-scan扫描使用上的容易忽略的use-default-filters

 

问题

如下方式可以成功扫描到@Controller注解的Bean,不会扫描@Service/@Repository的Bean。正确

 

Java代码  复制代码  收藏代码
  1.  <context:component-scan base-package="org.bdp.system.test.controller">    
  2.      <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>    
  3. </context:component-scan>  
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1.  <context:component-scan base-package="org.bdp.system.test.controller">   
  2.      <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>   
  3. </context:component-scan>  

  

但是如下方式,不仅仅扫描@Controller,还扫描@Service/@Repository的Bean,可能造成一些问题

 

Java代码  复制代码  收藏代码
  1.  <context:component-scan base-package="org.bdp">    
  2.      <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>    
  3. </context:component-scan>  
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1.  <context:component-scan base-package="org.bdp">   
  2.      <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>   
  3. </context:component-scan>  

 

这个尤其在springmvc+spring+hibernate等集成时最容易出问题的地,最典型的错误就是:

事务不起作用

 

这是什么问题呢?

分析

1、<context:component-scan>会交给org.springframework.context.config.ContextNamespaceHandler处理;

 

Java代码  复制代码  收藏代码
  1. registerBeanDefinitionParser("component-scan"new ComponentScanBeanDefinitionParser());  
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. registerBeanDefinitionParser("component-scan"new ComponentScanBeanDefinitionParser());  

 

2、ComponentScanBeanDefinitionParser会读取配置文件信息并组装成org.springframework.context.annotation.ClassPathBeanDefinitionScanner进行处理;

3、如果没有配置<context:component-scan>的use-default-filters属性,则默认为true,在创建ClassPathBeanDefinitionScanner时会根据use-default-filters是否为true来调用如下代码:

 

Java代码  复制代码  收藏代码
  1.   protected void registerDefaultFilters() {   
  2. this.includeFilters.add(new AnnotationTypeFilter(Component.class));   
  3. ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();   
  4. try {   
  5.     this.includeFilters.add(new AnnotationTypeFilter(   
  6.             ((Class<? extends Annotation>) cl.loadClass("javax.annotation.ManagedBean")), false));   
  7.     logger.info("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");   
  8. }   
  9. catch (ClassNotFoundException ex) {   
  10.     // JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.   
  11. }   
  12. try {   
  13.     this.includeFilters.add(new AnnotationTypeFilter(   
  14.             ((Class<? extends Annotation>) cl.loadClass("javax.inject.Named")), false));   
  15.     logger.info("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");   
  16. }   
  17. catch (ClassNotFoundException ex) {   
  18.     // JSR-330 API not available - simply skip.   
  19. }   
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1.   protected void registerDefaultFilters() {  
  2. this.includeFilters.add(new AnnotationTypeFilter(Component.class));  
  3. ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();  
  4. try {  
  5.     this.includeFilters.add(new AnnotationTypeFilter(  
  6.             ((Class<? extends Annotation>) cl.loadClass("javax.annotation.ManagedBean")), false));  
  7.     logger.info("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");  
  8. }  
  9. catch (ClassNotFoundException ex) {  
  10.     // JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.  
  11. }  
  12. try {  
  13.     this.includeFilters.add(new AnnotationTypeFilter(  
  14.             ((Class<? extends Annotation>) cl.loadClass("javax.inject.Named")), false));  
  15.     logger.info("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");  
  16. }  
  17. catch (ClassNotFoundException ex) {  
  18.     // JSR-330 API not available - simply skip.  
  19. }  

 

 

可以看到默认ClassPathBeanDefinitionScanner会自动注册对@Component、@ManagedBean、@Named注解的Bean进行扫描。如果细心,到此我们就找到问题根源了。

 

 

4、在进行扫描时会通过include-filter/exclude-filter来判断你的Bean类是否是合法的:

 

Java代码  复制代码  收藏代码
  1. protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {   
  2.     for (TypeFilter tf : this.excludeFilters) {   
  3.         if (tf.match(metadataReader, this.metadataReaderFactory)) {   
  4.             return false;   
  5.         }   
  6.     }   
  7.     for (TypeFilter tf : this.includeFilters) {   
  8.         if (tf.match(metadataReader, this.metadataReaderFactory)) {   
  9.             AnnotationMetadata metadata = metadataReader.getAnnotationMetadata();   
  10.             if (!metadata.isAnnotated(Profile.class.getName())) {   
  11.                 return true;   
  12.             }   
  13.             AnnotationAttributes profile = MetadataUtils.attributesFor(metadata, Profile.class);   
  14.             return this.environment.acceptsProfiles(profile.getStringArray("value"));   
  15.         }   
  16.     }   
  17.     return false;   
  18. }  
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {  
  2.     for (TypeFilter tf : this.excludeFilters) {  
  3.         if (tf.match(metadataReader, this.metadataReaderFactory)) {  
  4.             return false;  
  5.         }  
  6.     }  
  7.     for (TypeFilter tf : this.includeFilters) {  
  8.         if (tf.match(metadataReader, this.metadataReaderFactory)) {  
  9.             AnnotationMetadata metadata = metadataReader.getAnnotationMetadata();  
  10.             if (!metadata.isAnnotated(Profile.class.getName())) {  
  11.                 return true;  
  12.             }  
  13.             AnnotationAttributes profile = MetadataUtils.attributesFor(metadata, Profile.class);  
  14.             return this.environment.acceptsProfiles(profile.getStringArray("value"));  
  15.         }  
  16.     }  
  17.     return false;  
  18. }  

 

首先通过exclude-filter 进行黑名单过滤;

然后通过include-filter 进行白名单过滤;

否则默认排除。

 

结论

Java代码  复制代码  收藏代码
  1. <context:component-scan base-package="org.bdp">    
  2.      <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>    
  3. </context:component-scan>  
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <context:component-scan base-package="org.bdp">   
  2.      <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>   
  3. </context:component-scan>  

 

为什么这段代码不仅仅扫描@Controller注解的Bean,而且还扫描了@Component的子注解@Service、@Reposity。因为use-default-filters默认为true。所以如果不需要默认的,则use-default-filters=“false”禁用掉。

 

 

请参考

《SpringMVC + spring3.1.1 + hibernate4.1.0 集成及常见问题总结》 

《第三章 DispatcherServlet详解 ——跟开涛学SpringMVC》中的ContextLoaderListener初始化的上下文和DispatcherServlet初始化的上下文关系。

 

如果在springmvc配置文件,不使用cn.javass.demo.web.controller前缀,而是使用cn.javass.demo,则service、dao层的bean可能也重新加载了,但事务的AOP代理没有配置在springmvc配置文件中,从而造成新加载的bean覆盖了老的bean,造成事务失效。只要使用use-default-filters=“false”禁用掉默认的行为就可以了。

 

问题不难,spring使用上的问题。总结一下方便再遇到类似问题的朋友参考。

 

 

========================

http://my.oschina.net/u/1012289/blog/129298

自己看了官方文档,也到网上查了下,目前理解如下:   
<context:component-scan/>和<mvc:annotation-driven/>: 
<mvc:annotation-driven/>相当于注册了DefaultAnnotationHandlerMapping和AnnotationMethodHandlerAdapter两个bean,配置一些messageconverter。即解决了@Controller注解的使用前提配置。  

<context:annotation-config/>是对包进行扫描,实现注释驱动Bean定义,同时将bean自动注入容器中使用。即解决了@Controller标识的类的bean的注入和使用。  

一开始我在写配置的时候,只写了<context:component-scan/>,并没有使用<mvc:annotation-driven/>,servlet拦截*.do,.do请求可以被正确捕捉和处理。代码如下  
mvc-servlet.xml  

Java代码    收藏代码
  1. <context:component-scan base-package="com"></context:component-scan>  



web.xml  

Java代码    收藏代码
  1. <servlet>  
  2.     <servlet-name>mvc</servlet-name>  
  3.     <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>  
  4.     <load-on-startup>1</load-on-startup>  
  5. </servlet>  
  6. <servlet-mapping>  
  7.     <servlet-name>mvc</servlet-name>  
  8.     <url-pattern>*.do</url-pattern>  
  9. </servlet-mapping>  




后来为了解决静态资源访问的问题,servlet改成了拦截所有请求,即/,并添加了默认的servlet,这时候*.do请求不能被控制器捕捉了,页面错误为404。直到添加了<mvc:annotation-driven/>之后,.do请求才又能被正确捕捉和处理。代码如下  
mvc-servlet.xml  

Java代码    收藏代码
  1. <context:component-scan base-package="com"></context:component-scan>  
  2. <mvc:annotation-driven/>  
  3. <mvc:resources mapping="/styles/**" location="/WEB-INF/resource/styles/"/>  
  4. <mvc:default-servlet-handler/>  



web.xml  

Java代码    收藏代码
  1. <servlet>  
  2.     <servlet-name>mvc</servlet-name>  
  3.     <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>  
  4.     <load-on-startup>1</load-on-startup>  
  5. </servlet>  
  6. <servlet-mapping>  
  7.     <servlet-name>mvc</servlet-name>  
  8.     <url-pattern>/</url-pattern>  
  9. </servlet-mapping>  



是什么原因造成这种区别的呢?为什么一开始没用<mvc:annotation-driven/>的时候可以,添加了默认servlet之后就不行了呢?

<context:annotation-config/>和<context:component-scan/>:

在基于主机方式配置Spring的配置文件中,你可能会见到<context:annotation-config/>这样一条配置,他的作用是式地向 Spring 容器注册

AutowiredAnnotationBeanPostProcessorCommonAnnotationBeanPostProcessor

PersistenceAnnotationBeanPostProcessor 以及 RequiredAnnotationBeanPostProcessor  4 BeanPostProcessor

注册这4 BeanPostProcessor的作用,就是为了你的系统能够识别相应的注解。

例如:

如果你想使用@Autowired注解,那么就必须事先在 Spring 容器中声明 AutowiredAnnotationBeanPostProcessor Bean。传统声明方式如下

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

如果想使用@ Resource @ PostConstruct@ PreDestroy等注解就必须声明CommonAnnotationBeanPostProcessor

如果想使用@PersistenceContext注解,就必须声明PersistenceAnnotationBeanPostProcessorBean

如果想使用 @Required的注解,就必须声明RequiredAnnotationBeanPostProcessorBean。同样,传统的声明方式如下:

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

一般来说,这些注解我们还是比较常用,尤其是Antowired的注解,在自动注入的时候更是经常使用,所以如果总是需要按照传统的方式一条一条配置显得有些繁琐和没有必要,于是spring给我们提供<context:annotation-config/>的简化配置方式,自动帮你完成声明。

   不过,呵呵,我们使用注解一般都会配置扫描包路径选项

<context:component-scan base-package=”XX.XX”/> 

    该配置项其实也包含了自动注入上述processor的功能,因此当使用 <context:component-scan/> 后,就可以将 <context:annotation-config/> 移除了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值