package com.niewj.config; import com.niewj.bean.Person; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.FilterType; import org.springframework.stereotype.Controller; @Configuration @ComponentScan("com.niewj") public class MainConfig { @Bean public Person person() { return new Person("張三", 22); } }
(0). 常规: @ComponentScan(value="com.niewj")
(1). FilterType.ANNOTATION
只排除注解 value
+ excludeFilters
@ComponentScan( // 只排除: value = "com.niewj", excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Controller.class)} )
(2). FilterType.ANNOTATION
只过滤注解: 需要加上 value
+ useDefaultFilters=false
+ includeFilters
@ComponentScan( // 只包含: 必须要写 useDefaultFilters 否则不生效 value = "com.niewj", useDefaultFilters = false, includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Controller.class)} )
(3). FilterType.ASSIGNABLE_TYPE
:制定具体的类型, includeFilters 和 excludeFilters 本身就是个数组!
@ComponentScan( // 只包含: 必须要写 useDefaultFilters 否则不生效 value = "com.niewj", useDefaultFilters = false, includeFilters = { @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Controller.class), @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = BookService.class) } )
@Test public void testTypeFilter() { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MainConfig.class); Arrays.stream(ctx.getBeanDefinitionNames()).forEach(System.out::println); }
输出如下:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor org.springframework.context.annotation.internalAutowiredAnnotationProcessor org.springframework.context.annotation.internalCommonAnnotationProcessor org.springframework.context.event.internalEventListenerProcessor org.springframework.context.event.internalEventListenerFactory mainConfig bookController person
MainConfig.java:
package com.niewj.config; import com.niewj.bean.Person; import com.niewj.util.MyComponentScanTypeFilter; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.FilterType; @Configuration @ComponentScan(value = "com.niewj", useDefaultFilters = false, includeFilters = { @ComponentScan.Filter(type = FilterType.CUSTOM, classes = MyComponentScanTypeFilter.class) } ) public class MainConfig { @Bean public Person person() { return new Person("張三", 22); } }
主要看 MyComponentScanTypeFilter的类声明: 它的判断逻辑是满足一下两点, 则匹配!
package com.niewj.util; import com.niewj.controller.BaseController; import org.springframework.core.type.AnnotationMetadata; 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; import java.io.IOException; /** * 自定义 ComponentScan方式: */ public class MyComponentScanTypeFilter implements TypeFilter { /** * 此处的判断逻辑是: * 如果 * 1. 类是BaseController的子类 * 2. && 注解包含@Controller, 则匹配! * * @param metadataReader 获取到的当前类的注解信息 * @param metadataReaderFactory 可获取到其他类信息的工厂 * @return * @throws IOException */ @Override public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException { // 1. 获取当前类的注解信息 AnnotationMetadata annoMetadata = metadataReader.getAnnotationMetadata(); // 2. 获取当前正在扫描的类信息: ClassMetadata classMetadata = metadataReader.getClassMetadata(); if (isBaseController(classMetadata) && hasControllerAnnotation(annoMetadata)) { return true; } return false; } /** * 条件1: 正在扫描的类 是不是 BaseController的子类 * * @param classMetadata * @return */ private boolean isBaseController(ClassMetadata classMetadata) { // 3. 正在扫描的类名称 String className = classMetadata.getClassName(); // 4. 正在扫描的类的父类, 格式: BookController->com.niewj.controller.BaseController String superClassName = classMetadata.getSuperClassName(); return superClassName.contains(BaseController.class.getSimpleName()); } /** * 判断注解中有无Controller "org.springframework.stereotype.Controller" * * @param annotationMetadata * @return */ private boolean hasControllerAnnotation(AnnotationMetadata annotationMetadata) { return annotationMetadata.getAnnotationTypes().stream().anyMatch(e -> e.equals("org.springframework.stereotype.Controller")); } }
小结: ComponentScan扫描大致常用有这么几类:
1.普通@ComponentScan(value="com.niewj")
2.注解过滤排除: @ComponentScan(value="com.niewj", excludeFilters={filter1, filter2,...})
3.注解过滤包含: @ComponentScan(value="com.niewj", includeFilters={filter1, filter2, ...})
其中的 Filter 包含
(1). 注解过滤匹配: type = FilterType.ANNOTATION
(2). 指定的类名比配: type=FilterType.ASSIGNABLE_TYPE
(3).自定义类型匹配: type=FilterType.CUSTOM 如示例中的:
MyComponentScanTypeFilter implements `TypeFilter`
(4). type=FilterType.ASPECTJ (不常用)
(5). 正则匹配 type=FilterType.REGEX (不常用)