乐趣区

Spring注解扫描ComponentScan

当我们使用 Spring IOC 时, 我们通常需要先在组件上添加模式注解, 如 @Component、@Controller、@Service、@Repository、@Configuration 等将对象注入到 Spring 容器中, 而这时程序需要知道它将扫描哪些组件. 而 @ComponentScan 注解即用来作为这个边界划分的角色. 而此注解也是使用 xml 配置文件 <context:component-scan/> 的替代.


1. 默认扫描

一般我们先创建一个配置类, 并在配置类上添加 @ComponentScan 注解, 给注解默认会扫描该类所在的包下所有的配置类, 而这也是我们为什么一般默认将 SpringBoot 的引导类放在最外层的原因

@Configuration
@ComponentScan
public class SpringConfiguration { }

----------------------------------------------------------------------------------------------------------------------

@org.junit.Test
    public void test2() throws IOException {ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfiguration.class);
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {System.out.println(beanDefinitionName);
        }
    }


2. 指定扫描

之前提到过,@ComponentScan注解会默认扫描配置类所在包下的所有配置类, 如果我们的配置类不是在最外层, 那么我们就会出现在当前包以为的组件不能扫描到的情况发生. 这时我们可以使用此注解的 value 属性值来指定需要扫描的包 —@Component("com.lsy")就可以扫描指定包下的所有组件了. 其次我们也可以使用此注解的 basePackage 属性, 它是 value 属性的别名, 另外使用 basePackages 属性我们则可以一次性指定多个包进行扫描


3. 过滤扫描

我们可以通过属性 excludeFiltersincludeFilters来按照规则排除指定的组件扫描

  • excludeFilters: 按指定规则排除某些组件的扫描
  • includeFilters: 按指定规则只扫描某些组件

1. excludeFilters

@Configuration
@ComponentScan(value = "com.lsy",excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,value = Controller.class)})
public class SpringConfiguration {}

我们可以发现 Controller 标注的组件被排除在外了


2. includeFilters

@Configuration
@ComponentScan(value = "com.lsy",includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,value = Controller.class)})
public class SpringConfiguration {}

这里我们发现好像规则并没有起作用, 其原因是:@Controller、@Service、@Repository、@Configuration注解都是通过 @Component 派生出来的, 所以他们除了是他们自身, 同样是一个 @Component, 所以这里需要通过另一个属性useDefaultFilters = false 才能得到我们想要的结果

@Configuration
@ComponentScan(value = "com.lsy",includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,value = Controller.class)},useDefaultFilters = false)
public class SpringConfiguration {}


4. 自定义规律规则

在之前的过滤扫描中我们使用了 @Filter 注解, 此注解 type 属性是一个 FilterType 的枚举类型, 一共 5 个值:

  1. ANNOTATION: 按照注解方式
  2. ASSIGNABLE_TYPE: 按照指定类型的方式
  3. ASPECTJ: 按照 ASPECTJ 表达式的方式
  4. REGEX: 使用正则表达式的方式
  5. CUSTOM: 自定义的方式
@Configuration
@ComponentScan(value = "com.lsy",includeFilters = {@ComponentScan.Filter(type = FilterType.CUSTOM,value = {MyFilterType.class})},useDefaultFilters = false)
public class SpringConfiguration {

}

----------------------------------------------------------------------------------------------------------------------

public class MyFilterType implements TypeFilter {
    @Override
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
        // 获取当前扫描到的组件的注解元数据
        AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();

        // 获取当前扫描到的组件的元数据
        ClassMetadata classMetadata = metadataReader.getClassMetadata();

        // 获取当前扫描到的组件的资源信息
        Resource resource = metadataReader.getResource();
        if(classMetadata.getClassName().contains("User")){return true;}
        return false;
    }
}

首先我们将 @Filter 注解 type 属性值改为 CUSTOM, 并通过实现TypeFilter 接口来自定义过滤规则, 在此例中我们就能够只扫描类名中包含 User 字符串的组件

退出移动版