@ComponentScan注解 -【Spring底层原理】

* 指示是否应启用对带有{@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注解的组件不被扫描:

image-20210120115812025

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注解的组件才被扫描:

image-20210120133305643

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”的组件进行扫描:

image-20210120150558862

三、源码追踪


同样,咱们以AnnotationConfigApplicationContext类为入口,点进去跟踪源码:

image-20210120153916014

通过refresh()跟踪Bean 工厂的后置处理器调用:

image-20210120154049710

继续跟踪,查看源码,这里实例化并调用所有已注册的BeanFactoryPostProcessor

image-20210120154529999

继续跟踪,主方法中有一些加载顺序之类的,找到invokeBeanDefinitionRegistryPostProcessors,查看调用Bean的注册定义的后置处理器的方法,进入源码查看:

image-20210120154800082

继续跟踪,这里有个循环,会把所有的处理器拿出来进行处理:

image-20210120154908717

继续跟踪,可以看到是一个接口,进入查看实现类,我们可以看到一个配置Bean的定义,就是指我们Configuration配置的里面的一些Bean的定义:

image-20210120155028837

继续跟踪,processConfigBeanDefinitions类中可以看到Configuration类的解析器,通过parser.parse(candidates);把要扫描的东西进行解析

image-20210120155811376

继续跟踪,判断我们声明的是否是一个注解Bean,是的话,再进行解析

image-20210120155951900

继续跟踪:

image-20210120160043671

继续跟踪,在processConfigurationClass方法中找到和配置相关的方法:

image-20210120160159810

继续跟踪,可以看到和@ComponentScan注解注解相关的东西了,我们进入componentScanParser.parse看其具体的解析方法:

image-20210120160559967

继续跟踪,查看构造方法:

最后

Java架构进阶面试及知识点文档笔记

这份文档共498页,其中包括Java集合,并发编程,JVM,Dubbo,Redis,Spring全家桶,MySQL,Kafka等面试解析及知识点整理

image

Java分布式高级面试问题解析文档

其中都是包括分布式的面试问题解析,内容有分布式消息队列,Redis缓存,分库分表,微服务架构,分布式高可用,读写分离等等!

image

互联网Java程序员面试必备问题解析及文档学习笔记

image

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)领取


  1. A-Za-z. ↩︎

  2. A-Za-z. ↩︎

### 回答1: @componentscan注解报红可能是因为以下原因: 1. 未正确导入相关依赖:@componentscan注解Spring框架中的注解,需要在项目中导入相关的Spring依赖。 2. 未正确配置扫描路径:@componentscan注解需要指定要扫描的包路径,如果路径不正确或者不存在,就会报红。 3. 未在配置文件中启用自动扫描:在Spring框架中,@componentscan注解是用来开启自动扫描的,需要在Spring的配置文件中启用自动扫描功能。 解决方法: 1. 检查项目中是否已正确导入相关依赖,如果未导入,需要手动添加相关依赖。 2. 检查@componentscan注解中指定的包路径是否正确,如果路径不正确或者不存在,需要修改路径。 3. 确认在Spring的配置文件中已启用自动扫描功能,如果未启用,需要添加配置启用自动扫描功能。 以上是@componentscan注解报红的可能原因和解决方法,希望对您有所帮助。 ### 回答2: @componentscan注解Spring框架中常用的注解之一,用于自动扫描指定包下的所有组件并注册为Spring容器的Bean。若在使用过程中遇到该注解报红,一般有以下几种原因: 1. 缺少依赖:@componentscan注解需要依赖Spring框架的相关包才能生效,如果项目中只引入了部分Spring相关的包或版本不兼容,就可能出现报红的情况。可以通过检查pom.xml文件中的依赖,确认是否引入了正确的Spring相关包,并且版本是否正确。 2. 扫描路径配置错误:@componentscan注解中的value属性用于指定需要扫描的包路径,默认为当前使用该注解的类所在的包及其子包。如果value属性配置错误,或者指定的包路径不存在,则会出现报红的情况。可以通过检查注解中配置的扫描路径是否正确,或者检查该路径下是否存在需要扫描的组件。 3. 项目结构问题:如果项目的结构不太规范或者不符合Spring框架的规范,就有可能出现@componentscan注解报红的情况。例如,某些组件或类没有按照规范放置在指定的目录下,就会导致注解扫描不到需要的类或组件。可以通过检查项目结构是否符合规范,或者调整组件或类的位置来解决该问题。 总之,遇到@componentscan注解报红的情况,需要仔细检查代码和项目结构,将问题解决掉后才能保证程序正常运行。同时需要注意,报红并不一定意味着一定有问题,可能只是IDE的提示,可以通过忽略或者关闭相关的提示来避免影响开发。 ### 回答3: 在Spring中,@ComponentScan注解是用来扫描指定包及其子包中的组件(@Component,@Service,@Repository,@Controller等)并自动注册为Bean的注解。但是,如果出现了@ComponentScan注解报红的情况,可能有以下几种原因: 1. 缺少必要的依赖:Spring框架是由多个模块组成的,如spring-context、spring-core等。在使用@ComponentScan注解时,需要确保所需的模块已正确引入且版本与当前项目的Spring版本匹配。如果缺少必要的依赖,就会导致无法识别@ComponentScan注解。 2. 未正确配置扫描路径:@ComponentScan注解需要指定要扫描的包及其子包路径。如果没有正确配置扫描路径,就会导致注解不起作用。可以通过在注解中指定具体的扫描路径来解决此问题。 3. 存在语法错误:如果注解语法有错误或书写不正确,会导致编译时报错,从而导致@ComponentScan注解出现报红的情况。可以通过检查注解语法并将其正确书写来解决此问题。 4. IDE问题:有时IDE的版本或其他设置可能会导致注解报错。可以尝试更新IDE版本或检查IDE设置,以解决这种问题。 综上所述,针对@ComponentScan注解报红的情况,应该通过检查项目依赖、扫描路径、注解语法等方面来解决问题。如果无法解决,可以考虑寻求帮助或咨询专业人士。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值