当我们使用
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. 过滤扫描
我们可以通过属性
excludeFilters
和includeFilters
来按照规则排除指定的组件扫描
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
个值:
ANNOTATION
: 按照注解方式ASSIGNABLE_TYPE
: 按照指定类型的方式ASPECTJ
: 按照 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
字符串的组件