【spring】之基于注解@ComponentScan的一些使用

本文深入探讨Spring框架中@ComponentScan注解的使用方法,包括如何通过注解、类类型、自定义规则等进行组件扫描过滤,以及如何实现TypeFilter接口自定义过滤规则。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

基于xml形式ComponentScan的使用如下

 

<context:component-scan base-package="com.luna" use-default-filters="false">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

基于注解@ComponentScan的使用

复制代码

@Configuration

/*@ComponentScan(value = "com.luna", includeFilters = {

   // @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class}),
   // @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,value ={com.luna.service.PersonService.class} )
   @ComponentScan.Filter(type = FilterType.CUSTOM,value = {MyFilter.class})
 },useDefaultFilters = false)*/

@ComponentScan(value = "com.luna", 

    //排除某些类
    excludeFilters = {
       //排除Controller注解标注的类 
    @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class}),
       //排除指定类型的类 
       @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,value ={com.luna.service.PersonService.class} )
})
public class ScanConfig {
}

复制代码

 

测试

复制代码

@Test
    public void test(){
        AnnotationConfigApplicationContext applicationContext = 
                new AnnotationConfigApplicationContext(ScanConfig.class);
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        Arrays.asList(beanDefinitionNames).stream().forEach(x->System.out.println("扫描到的Bean---"+x));
    }

复制代码

 

 

 

@ComponentScan一些常用参数

//基本属性 value/basePackages:指定一组要扫描的包,将扫描这些包及其子包下的文件.(默认基包为配置类所在的包)

classes:直接指定扫描的一些类,这些类所在的包及其子包也会被扫描。

nameGenerator:指定一个默认扫描组件的命名类, 默认命名使用组件类名第一个字小写。

excludeFilters:指定扫描的时候排除某些类,按什么规则,需要一组@ComponentScan.Filter的注解配置,每个@Filter可以配置一组过滤规则,多个@Filter可以基于正则/注解/具体类配置不同的过滤规则。

includeFilters:指定扫描的时候,只包含某些类。

useDefaultFilters 自动扫描Controller Component Service Resposity 这四个注解
所以在不指定明确包的情况下如 com.luna 全包扫描,会扫描到Controller Component Service Resposity 四个注解

 

一、注解说明

@ComponentScan:会自动扫描包路径下面的所有@Controller、@Service、@Repository、@Component 的类

它里面的属性: value指定扫描的包,includeFilters包含那些过滤,excludeFilters不包含那些过滤,useDefaultFilters默认的过滤规则是开启的,如果我们要自定义的话是要关闭的。其中@Filters是一个过滤器的接口。

@Filters 指过滤规则,FilterType指定过滤的规则(

            FilterType.ANNOTATION:按照注解

            FilterType.ASSIGNABLE_TYPE:按照给定的类型;

            FilterType.ASPECTJ:使用ASPECTJ表达式

            FilterType.REGEX:使用正则指定

            FilterType.CUSTOM:使用自定义规则)

            classes指定过滤的类

示列如下:

package com.guang.config;
 
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import com.guang.entity.Person;
 
@Configuration
// @ComponentScan("包路径") 会自动扫描包路径下面的所有@Controller、@Service、@Repository、@Component 的类
// includeFilters 指定包含扫描的内容
// excludeFilters 指定不包含的内容
// @Filter 指定过滤规则,type指定扫描的规则(注解,正则,自定义,ASPECTJ表达式),classes指定的扫描的规则类
@ComponentScan(basePackages = {"com.guang"},
        includeFilters = @Filter(type = FilterType.ANNOTATION, classes = {Controller.class}),
        excludeFilters = @Filter(type = FilterType.ANNOTATION, classes = {Repository.class}),
        includeFilters = @Filter(type = FilterType.CUSTOM, classes = {FilterCustom.class}),
        useDefaultFilters = false)
public class Myconfig {
 
    @Bean("person")
    public Person person01() {
        return new Person("aiha", 25);
    }
 
}
二、如果我们在使用自定义(includeFilters = @Filter(type = FilterType.CUSTOM, classes = {自己定义的类}))过滤规则的时候,我们自己定义的类要实现TypeFilter接口,例如:

package com.guang.config;
 
import java.io.IOException;
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.TypeFilter;
 
/**
 * 自定义的过滤规则,在自动扫描的时候用,自定义过滤的时候不在使用默认的规则了
 *
 * @ClassName FilterCustom
 * @author xxx
 * @date xxx
 * @version xxx
 */
public class FilterCustom implements TypeFilter {
 
    /**
     * 
     * @Title: match
     * @Description: 覆盖方法注释标签说明
     * @param metadataReader 读取的当前正在扫描类的信息
     * @param metadataReaderFactory 类工厂中其它类的信息
     * @return
     * @throws IOException
     * @see org.springframework.core.type.filter.TypeFilter#match(org.springframework.core.type.classreading.MetadataReader,
     *      org.springframework.core.type.classreading.MetadataReaderFactory)
     */
    @Override
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
            throws IOException {
        // 获取当前类注解的信息
        // AnnotationMetadata metadata = metadataReader.getAnnotationMetadata();
        // 获取当前正在扫描类的信息
        ClassMetadata classMetadata = metadataReader.getClassMetadata();
        // 获取当前类路径的信息
        // Resource resource = metadataReader.getResource();
        if (classMetadata.getClassName().startsWith("person")) {
            return true;
        }
        return false;
    }
 
}

-

FilterType.ANNOTATION(默认)一组注解,命中所有使用该注解的类,{MyAnno.class}-
FilterType.ASSIGNABLE_TYPE一组具体类-
FilterType.ASPECTJ-一组表达式,使用Aspectj表达式命中类
FilterType.REGEX-一组表达式,使用正则命中类
FilterType.CUSTOM自定义的TypeFilter.-
### Spring @ComponentScan 注解 使用说明及常见问题解决方案 #### 一、@ComponentScan 注解概述 `@ComponentScan` 是 Spring 框架中的一个重要注解,主要用于自动扫描指定包及其子包下的类,并将其注册为 Spring 容器中的 Bean。默认情况下,Spring Boot 项目会基于 `@SpringBootApplication` 注解所在的包路径进行扫描,但如果需要自定义扫描范围,则可以通过 `@ComponentScan` 显式指定[^1]。 - **核心功能**:扫描带有特定注解(如 `@Component`、`@Service`、`@Repository` 和 `@Controller` 等)的类,并将它们注册为 Spring 容器中的 Bean。 - **注意事项**:如果目标类是接口而非具体实现类,即使标注了 `@Component` 注解,也无法被实例化为 Bean,因为接口本身无法直接实例化[^2]。 --- #### 二、@ComponentScan 的常用属性 以下是 `@ComponentScan` 注解的一些重要属性及其作用: 1. **basePackages** - 类型:字符串数组 (`String[]`) - 描述:指定需要扫描的包名列表。例如: ```java @ComponentScan(basePackages = {"com.example.package1", "com.example.package2"}) ``` 2. **basePackageClasses** - 类型:Class 数组 (`Class<?>[]`) - 描述:通过指定某些类来间接确定扫描的包路径。这些类所在的包会被作为根目录进行扫描。例如: ```java @ComponentScan(basePackageClasses = {MyClass1.class, MyClass2.class}) ``` 3. **useDefaultFilters** - 类型:布尔值 (`boolean`) - 描述:控制是否启用默认过滤规则,默认值为 `true`。如果设为 `false`,则需要显式定义过滤条件。 4. **includeFilters/excludeFilters** - 类型:Filter 数组 (`Filter[]`) - 描述:用于定义包含或排除的过滤规则。支持多种类型的过滤器,如按注解、类类型等筛选。例如: ```java @ComponentScan( includeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Controller.class), useDefaultFilters = false ) ``` 5. **resourcePattern** - 类型:字符串 (`String`) - 描述:定义扫描时匹配的资源模式,默认为 `/**/*.class`,即扫描所有 `.class` 文件。 --- #### 三、典型应用场景与代码示例 ##### 场景 1:覆盖默认扫描路径项目的包结构较为复杂,或者需要引入外部 jar 包中的组件时,可以使用 `@ComponentScan` 来扩展扫描范围。例如: ```java @ComponentScan(basePackages = {"com.external.lib", "com.myapp.service"}) public class AppConfig { } ``` ##### 场景 2:多重扫描不同包路径 有时需要同时扫描多个不相关的包路径,可通过重复使用 `@ComponentScan` 或利用 `@Repeatable` 特性完成。例如: ```java @ComponentScan("com.pwx.bean") @ComponentScan("com.pwx.bean1") public class MyConfig { public static void main(String[] args) { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class); String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames(); Arrays.stream(beanDefinitionNames).forEach(System.out::println); } } ``` 注意:上述写法在现代版本中可能更推荐使用 `@ComponentScans` 组合形式[^3]。 ##### 场景 3:定制化过滤规则 假设只希望扫描带 `@Controller` 注解的类,可配置如下: ```java @ComponentScan( basePackages = "com.myapp", includeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Controller.class), useDefaultFilters = false ) public class WebAppConfig { } ``` --- #### 四、常见问题及解决方法 1. **问题**: 引入第三方库后,部分 Bean 未被扫描到。 - **原因**: 默认扫描路径仅限于启动类所在包及其子包。 - **解决办法**: 使用 `@ComponentScan` 扩展扫描范围至目标包路径[^5]。 2. **问题**: 控制器类未被识别,导致 HTTP 请求返回 404 错误。 - **原因**: 启动类所在包之外的控制器类未被纳入扫描范围。 - **解决办法**: 确保 `@ComponentScan` 正确指定了包含控制器类的包路径。 3. **问题**: 接口类加了 `@Component` 注解却未能成为 Bean。 - **原因**: 接口无法直接实例化。 - **解决办法**: 提供具体的实现类并为其添加相应注解[^2]。 --- ### 总结 `@ComponentScan` 是一个强大的工具,可以帮助开发者灵活地管理 Spring 应用中的组件扫描行为。合理配置其属性能够显著提升开发效率,同时也需留意潜在陷阱以避免不必要的错误发生。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值