* 指示是否应启用对带有{@code @Component},{@ code @Repository},
* {@ code @Service}或{@code @Controller}注释的类的自动检测。
*/
boolean useDefaultFilters() default true;
/**
* 对被扫描的包或类进行过滤,若符合条件,不论组件上是否有注解,Bean对象都将被创建
* @ComponentScan(value = “com.onestar”,includeFilters = {
* @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class, Service.class}),
* @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {UserDao.class}),
* @ComponentScan.Filter(type = FilterType.CUSTOM, classes = {MyTypeFilter.class}),
* @ComponentScan.Filter(type = FilterType.ASPECTJ, pattern = “spring.annotation…*”),
* @ComponentScan.Filter(type = FilterType.REGEX, pattern = “1+Dao$”)
* },useDefaultFilters = false)
* useDefaultFilters 必须设为 false
*/
ComponentScan.Filter[] includeFilters() default {};
// 设置排除的过滤条件,指定扫描的时候按照什么规则排除哪些组件,排除要扫描的包,用法参考includeFilters
ComponentScan.Filter[] excludeFilters() default {};
/**
* 指定是否应注册扫描的Bean以进行延迟初始化。
* @ComponentScan(value = “com.onestar”,lazyInit = true)
*/
boolean lazyInit() default false;
// @Filter注解,用于 includeFilters 或 excludeFilters 的类型筛选器
@Retention(RetentionPolicy.RUNTIME)
@Target({})
public @interface Filter {
/**
* 要使用的过滤器类型,默认为 ANNOTATION 注解类型
* @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class, Service.class})
*/
FilterType type() default FilterType.ANNOTATION;
/**
* 过滤器的参数,参数必须为class数组,单个参数可以不加大括号
* 只能用于 ANNOTATION 、ASSIGNABLE_TYPE 、CUSTOM 这三个类型
* @ComponentScan.Filter(type = FilterType.ANNOTATION, value = {Controller.class, Service.class})
* @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {UserDao.class})
* @ComponentScan.Filter(type = FilterType.CUSTOM, classes = {MyTypeFilter.class})
*/
@AliasFor(“classes”)
Class<?>[] value() default {};
/**
* 作用同上面的 value 相同
* ANNOTATION 参数为注解类,如 Controller.class, Service.class, Repository.class
* ASSIGNABLE_TYPE 参数为类,如 UserDao.class
* CUSTOM 参数为实现 TypeFilter 接口的类 ,如 MyTypeFilter.class
* MyTypeFilter 同时还能实现 EnvironmentAware,BeanFactoryAware,BeanClassLoaderAware,ResourceLoaderAware
* 这四个接口
* EnvironmentAware
* 此方法用来接收 Environment 数据 ,主要为程序的运行环境,Environment 接口继承自 PropertyResolver 接口,
* 详细内容在下方
* @Override
* public void setEnvironment(Environment environment) {
* String property = environment.getProperty(“os.name”);
* }
*
* BeanFactoryAware
* BeanFactory Bean容器的根接口,用于操作容器,如获取bean的别名、类型、实例、是否单例的数据
* @Override
* public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
* Object bean = beanFactory.getBean(“BeanName”)
* }
*
* BeanClassLoaderAware
* ClassLoader 是类加载器,在此方法里只能获取资源和设置加载器状态
* @Override
* public void setBeanClassLoader(ClassLoader classLoader) {
* ClassLoader parent = classLoader.getParent();
* }
*
* ResourceLoaderAware
* ResourceLoader 用于获取类加载器和根据路径获取资源
* public void setResourceLoader(ResourceLoader resourceLoader) {
* ClassLoader classLoader = resourceLoader.getClassLoader();
* }
*/
@AliasFor(“value”)
Class<?>[] classes() default {};
/**
* 这个参数是 classes 或 value 的替代参数,主要用于 ASPECTJ 类型和 REGEX 类型
* ASPECTJ 为 ASPECTJ 表达式
* @ComponentScan.Filter(type = FilterType.ASPECTJ, pattern = “com.onestar…*”)
* REGEX 参数为 正则表达式
* @ComponentScan.Filter(type = FilterType.REGEX, pattern = “2+Dao$”)
*/
String[] pattern() default {};
}
}
1. excludeFilters=Filter[ ]
通过excludeFilters=Filter[ ]
来排除要扫描的包,在配置类注解中修改:
@Configuration
@ComponentScan(value = “com.onestar”,excludeFilters = {
@Filter(type = FilterType.ANNOTATION,classes = {Controller.class, Service.class})})
public class AppConfig {
}
-
type:表示过滤类型,这里是按照注解进行过滤
-
classes:表示过滤器参数,这里是过滤掉有@Controller和@Service注解的组件
查看源码我们可以得知,通过实现Filter接口的type属性用于设置过滤类型,默认值为
FilterType.ANNOTATION
,提供了这几个过滤类型:
FilterType.ANNOTATION
:按照注解过滤
FilterType.ASSIGNABLE_TYPE
:按照给定的类型过滤
FilterType.ASPECTJ
:按照ASPECTJ表达式过滤
FilterType.REGEX
:按照正则表达式过滤
FilterType.CUSTOM
:按照自定义规则过滤
classes和value属性为过滤器的参数,必须为class数组,类只能为以下三种类型:
- ANNOTATION 参数为注解类,如
Controller.class, Service.class, Repository.class
- ASSIGNABLE_TYPE 参数为类,如 UserDao.class
- CUSTOM 参数为实现 TypeFilter 接口的类 ,如 MyTypeFilter.class
通过上面的excludeFilters
注解配置,咱们再来运行一下测试类,打印信息如下,可以看到,标有@Controller和@Service注解的组件不被扫描:
2. includeFilters=filter[ ]
通过includeFilters=Filter[ ]
只需要包含要扫描的包,在配置类注解中修改,默认的规则是扫描value下所有的包,所以我们要禁用这个规则:
@Configuration
@ComponentScan(value = “com.onestar”,includeFilters = {
@Filter(type = FilterType.ANNOTATION,classes = {Controller.class, Service.class})},useDefaultFilters = false)
public class AppConfig {
}
useDefaultFilters = false
:禁用默认扫描规则
通过上面的includeFilters
注解配置,咱们再来运行一下测试类,打印信息如下,可以看到,标有@Controller和@Service注解的组件才被扫描:
3. `FilterType.CUSTOM`
上面提到,可以使用FilterType.CUSTOM
按照自定义规则进行过滤,通过源码,我们知道,可以实现TypeFilter的实现类来进行自定义过滤
public class MyTypeFilter implements TypeFilter {
/**
* @description TODO
* @author ONESTAR
* @date 2021/1/20 14:29
* @param metadataReader:读取到当前正在扫描的类的信息
* @param metadataReaderFactory:可以获取到其他任何类的信息
* @throws
* @return boolean
*/
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
// 获取当前类注解的信息
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
// 获取当前正在扫描的类的信息
ClassMetadata classMetadata = metadataReader.getClassMetadata();
// 获取当前类资源
Resource resource = metadataReader.getResource();
String className = classMetadata.getClassName();
// 指定包含“serv”的组件进行扫描
if(className.contains(“serv”)){
return true;
}
return false;
}
}
该实现类通过获取当前所有资源组件,并进行指定扫描,这里包含“serv”的组件进行扫描,然后修改配置类指定自定义扫描规则:
@Configuration
@ComponentScan(value = “com.onestar”,includeFilters = {
@Filter(type = FilterType.CUSTOM,classes = {MyTypeFilter.class})},useDefaultFilters = false)
public class AppConfig {
}
MyTypeFilter.class
:指定自定义过滤参数
运行测试类,可以看到打印信息,包含“serv”的组件进行扫描:
三、源码追踪
同样,咱们以AnnotationConfigApplicationContext
类为入口,点进去跟踪源码:
通过refresh()跟踪Bean 工厂的后置处理器调用:
继续跟踪,查看源码,这里实例化并调用所有已注册的
BeanFactoryPostProcessor
:
继续跟踪,主方法中有一些加载顺序之类的,找到invokeBeanDefinitionRegistryPostProcessors,查看调用Bean的注册定义的后置处理器的方法,进入源码查看:
继续跟踪,这里有个循环,会把所有的处理器拿出来进行处理:
继续跟踪,可以看到是一个接口,进入查看实现类,我们可以看到一个配置Bean的定义,就是指我们Configuration配置的里面的一些Bean的定义:
继续跟踪,
processConfigBeanDefinitions
类中可以看到Configuration
类的解析器,通过parser.parse(candidates);
把要扫描的东西进行解析
继续跟踪,判断我们声明的是否是一个注解Bean,是的话,再进行解析
继续跟踪:
继续跟踪,在
processConfigurationClass
方法中找到和配置相关的方法:
继续跟踪,可以看到和@ComponentScan注解注解相关的东西了,我们进入
componentScanParser.parse
看其具体的解析方法:
继续跟踪,查看构造方法:
最后
Java架构进阶面试及知识点文档笔记
这份文档共498页,其中包括Java集合,并发编程,JVM,Dubbo,Redis,Spring全家桶,MySQL,Kafka等面试解析及知识点整理
Java分布式高级面试问题解析文档
其中都是包括分布式的面试问题解析,内容有分布式消息队列,Redis缓存,分库分表,微服务架构,分布式高可用,读写分离等等!
互联网Java程序员面试必备问题解析及文档学习笔记
Java架构进阶视频解析合集
找小编(vip1024c)领取
/img-blog.csdnimg.cn/img_convert/17ab12d330065df9aee5e74fd8337502.png)
继续跟踪,查看构造方法:
最后
Java架构进阶面试及知识点文档笔记
这份文档共498页,其中包括Java集合,并发编程,JVM,Dubbo,Redis,Spring全家桶,MySQL,Kafka等面试解析及知识点整理
[外链图片转存中…(img-hyxTfcT9-1721629180222)]
Java分布式高级面试问题解析文档
其中都是包括分布式的面试问题解析,内容有分布式消息队列,Redis缓存,分库分表,微服务架构,分布式高可用,读写分离等等!
[外链图片转存中…(img-yOakj2OK-1721629180223)]
互联网Java程序员面试必备问题解析及文档学习笔记
[外链图片转存中…(img-KnR9yFUO-1721629180223)]
Java架构进阶视频解析合集
找小编(vip1024c)领取