http://www.iteye.com/problems/66133

<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>  
<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-name>mvc</servlet-name>
	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
	<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
	<servlet-name>mvc</servlet-name>
	<url-pattern>*.do</url-pattern>
</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/>  
<context:component-scan base-package="com"></context:component-scan>
<mvc:annotation-driven/>
<mvc:resources mapping="/styles/**" location="/WEB-INF/resource/styles/"/>
<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>  
<servlet>
	<servlet-name>mvc</servlet-name>
	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
	<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
	<servlet-name>mvc</servlet-name>
	<url-pattern>/</url-pattern>
</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>  
 <context:component-scan base-package="org.bdp.system.test.controller"> 
     <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> 
</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>  
 <context:component-scan base-package="org.bdp"> 
     <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> 
</context:component-scan>

 

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

事务不起作用

 

这是什么问题呢?

分析

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

 

Java代码 复制代码  收藏代码
  1. registerBeanDefinitionParser("component-scan"new ComponentScanBeanDefinitionParser());  
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. }   
    protected void registerDefaultFilters() {
		this.includeFilters.add(new AnnotationTypeFilter(Component.class));
		ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
		try {
			this.includeFilters.add(new AnnotationTypeFilter(
					((Class<? extends Annotation>) cl.loadClass("javax.annotation.ManagedBean")), false));
			logger.info("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
		}
		catch (ClassNotFoundException ex) {
			// JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.
		}
		try {
			this.includeFilters.add(new AnnotationTypeFilter(
					((Class<? extends Annotation>) cl.loadClass("javax.inject.Named")), false));
			logger.info("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
		}
		catch (ClassNotFoundException ex) {
			// JSR-330 API not available - simply skip.
		}
	}

 

 

可以看到默认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. }  
	protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
		for (TypeFilter tf : this.excludeFilters) {
			if (tf.match(metadataReader, this.metadataReaderFactory)) {
				return false;
			}
		}
		for (TypeFilter tf : this.includeFilters) {
			if (tf.match(metadataReader, this.metadataReaderFactory)) {
				AnnotationMetadata metadata = metadataReader.getAnnotationMetadata();
				if (!metadata.isAnnotated(Profile.class.getName())) {
					return true;
				}
				AnnotationAttributes profile = MetadataUtils.attributesFor(metadata, Profile.class);
				return this.environment.acceptsProfiles(profile.getStringArray("value"));
			}
		}
		return false;
	}

 

首先通过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>  
<context:component-scan base-package="org.bdp"> 
     <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> 
</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/> 移除了。

 

 

 

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐