当我们使用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);
        }
    }

image.png


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 {

}

image.png

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

2. includeFilters

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

}

image.png

这里我们发现好像规则并没有起作用,其原因是:@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 {

}

image.png


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;
    }
}

image.png

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

NTFA
24 声望3 粉丝

自我约束,刻意练习


引用和评论

0 条评论