当我们使用 Spring IOC
时,我们通常需要先在组件上添加模式注解,如 @Component、@Controller、@Service、@Repository、@Configuration
等将对象注入到 Spring
容器中,而这时程序需要知道它将扫描哪些组件.而 @ComponentScan
注解即用来作为这个边界划分的角色.而此注解也是使用xml配置文件 <context:component-scan/>
的替代.
一般我们先创建一个配置类,并在配置类上添加 @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); } }
之前提到过, @ComponentScan
注解会默认扫描配置类所在包下的所有配置类,如果我们的配置类不是在最外层,那么我们就会出现在当前包以为的组件不能扫描到的情况发生.这时我们可以使用此注解的 value
属性值来指定需要扫描的包--- @Component("com.lsy")
就可以扫描指定包下的所有组件了.其次我们也可以使用此注解的 basePackage
属性,它是 value
属性的别名,另外使用 basePackages
属性我们则可以一次性指定多个包进行扫描
我们可以通过属性 excludeFilters
和 includeFilters
来按照规则排除指定的组件扫描
excludeFilters includeFilters
@Configuration @ComponentScan(value = "com.lsy",excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,value = Controller.class)}) public class SpringConfiguration { }
我们可以发现 Controller
标注的组件被排除在外了
@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 { }
在之前的过滤扫描中我们使用了 @Filter
注解,此注解 type
属性是一个 FilterType
的枚举类型,一共 5
个值:
ANNOTATION ASSIGNABLE_TYPE ASPECTJ REGEX 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
字符串的组件