springmvc配置文件中context:component-scan扫描使用上的容易忽略的use-default-filters

Spring扫描组件详解
本文深入解析Spring中使用<context:component-scan>时如何精确控制组件扫描范围,特别是如何仅扫描@Controller注解的Bean而避免扫描@Service/@Repository等其他类型Bean的方法。

问题

如下方式可以成功扫描到@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>  

  

但是如下方式,不仅仅扫描@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>  

 

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

事务不起作用

 

这是什么问题呢?

分析

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

 

Java代码  收藏代码
  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. }  

 

 

可以看到默认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. }  

 

首先通过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>  

 

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

<think>嗯,用户现在的问题是SpringMVCXML配置文件头标错,也就是XML文件的头部声明或者命名空间配置有问题。需要先理解用户的具体情况。根据用户提供的引用内容,尤其是引用[1],里面提到SpringMVC配置文件默认位于WEB-INF下,并且命名规则是servlet-name加-servlet.xml。例如,如果servlet-name是SpringMVC,那么配置文件就是springMVC-servlet.xml。 首先,用户可能遇到的错误可能是XML头部声明不正确,比如版本号或者编码错误。例如,XML的版本声明应该是<?xml version="1.0" encoding="UTF-8"?>,如果这里写错了,比如编码写成其他格式,或者版本号不对,解析器会报错。 另外,命名空间的声明可能不正确。比如在引用[1]中的web.xml配置中,使用了正确的命名空间和schemaLocation。而SpringMVC配置文件可能需要引入正确的命名空间,比如xmlns:contextxmlns:mvc等,如果这些命名空间声明缺失或者URI错误,会导致配置文件解析失败。 还要考虑用户是否正确引用了XSD文件。有时候,网络问题可能导致无法下载XSD文件,这时候可以改用本地路径或者使用正确的版本。例如,Spring 5的XSD版本和之前的可能不同,如果用户用了旧版本的XSD,而实际依赖的是新版本的Spring库,就会出现不匹配的问题。 另外,用户可能在配置组件扫描时,比如context:component-scan的base-package设置错误,或者没有正确使用use-default-filters属性,导致扫描不到或重复扫描,从而引发配置错误。引用[2]和[3]提到事务管理无效的问题,可能与组件扫描范围有关,但这里用户的问题是关于XML头部的错误,所以可能关联不大,但需要确认是否扫描配置正确。 还要检查XML文件的语法是否正确,比如标签是否正确闭合,属性是否正确拼写。例如,是否在定义beans的时候漏掉了结束标签,或者属性名写错了,比如把xsi:schemaLocation写成了其他形式。 可能用户复制了不完整的配置示例,导致头部信息缺失。比如,正确的Spring配置文件头部应该包括xmlns、xsi:schemaLocation等,如果用户漏掉了某个部分,就会导致解析错误。 另外,用户可能混淆了不同版本的Spring配置。比如,Spring 4和Spring 5的命名空间URI可能不同,使用旧版本的URI会导致错误。例如,Spring 5的命名空间是http://www.springframework.org/schema/beans/spring-beans.xsd,而旧版本可能没有.xsd后缀或者版本号不同。 解决方案方面,首先需要提供一个正确的XML配置文件模板,确保头部声明正确。然后检查常见的错误点,比如命名空间是否正确、schemaLocation的URI是否正确、组件扫描的包路径是否正确等。同时,建议用户使用IDE的自动补全功能来减少手写错误,或者通过Spring官方文档核对配置。 用户可能遇到的另一个问题是网络问题导致无法下载XSD文件,这时候可以建议用户配置本地XSD文件或者使用正确的版本,或者检查IDE的设置是否允许联网下载。 最后,可能需要提醒用户注意XML的语法细节,比如大小写、空格、特殊字符转义等,这些都可能引起解析错误。例如,在XML中属性值必须用引号包围,标签必须正确嵌套等。</think>### Spring MVC XML配置文件头错误的原因及解决方案 在Spring MVC项目中,`springmvc-servlet.xml`配置文件的头部声明错误通常由**命名空间缺失**、**版本不匹配**或**XSD文件加载失败**引起。以下是具体原因及对应的解决方案: --- #### **一、典型错误表现** 1. **IDE标红提示**:XML头部出现红色波浪线提示,如`Cannot resolve ...`或`Unknown namespace` 2. **启动报错**:应用启动时抛出`org.xml.sax.SAXParseException`,提示命名空间或schema验证失败 3. **配置不生效**:Spring MVC功能(如组件扫描、视图解析)无法正常加载 --- #### **二、常见错误原因与解决方案** ##### **1. 命名空间声明不完整** **错误现象**:缺失关键命名空间(如`context`、`mvc`)导致配置无法解析 **解决方案**:使用完整的命名空间声明模板: ```xml <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> </beans> ``` ##### **2. XSD版本与Spring版本不匹配** **错误现象**:使用Spring 5但引用了Spring 4的XSD文件 **解决方案**:根据Spring版本选择正确的XSD路径(以Spring 5为例): ```xml <!-- 注意版本号(如5.3.x) --> http://www.springframework.org/schema/beans/spring-beans.xsd → http://www.springframework.org/schema/beans/spring-beans-5.3.x.xsd ``` ##### **3. 网络问题导致XSD加载失败** **错误现象**:`schema_reference.4`错误,提示无法获取XSD文件 **解决方案**(任选一种): - **启用本地缓存**:在IDE中配置XML Catalog(推荐使用IntelliJ/Eclipse的自动缓存) - **离线模式**:下载对应XSD文件到本地,修改`schemaLocation`路径: ```xml xsi:schemaLocation=" http://www.springframework.org/schema/beans file:///D:/spring/spring-beans-5.3.x.xsd" ``` ##### **4. 组件扫描配置冲突** **错误现象**:与Spring父容器扫描范围重叠(如重复扫描@Service组件)[^3] **正确配置**(仅在Spring MVC配置扫描控制器): ```xml <context:component-scan base-package="com.example.controller" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan> ``` --- #### **三、验证配置正确性的方法** 1. **IDE校验**:确保XML文件无红色错误提示(需联网或配置本地XSD) 2. **启动日志检查**:查看Tomcat日志中是否包含`Loading XML bean definitions`成功信息 3. **功能验证**:测试`@Controller`是否能被正确加载(如访问URL是否触发控制器方法) --- #### **四、标准配置模板(Spring 5)** ```xml <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-5.3.x.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-5.3.x.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-5.3.x.xsd"> <!-- 启用注解驱动 --> <mvc:annotation-driven/> <!--扫描控制器 --> <context:component-scan base-package="com.example.web" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan> <!-- 视图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/views/"/> <property name="suffix" value=".jsp"/> </bean> </beans> ``` ---
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值