Spring之为什么标记了@Component的类会被扫描成 bean

本文解析Spring框架如何通过@ComponentScan注解扫描并实例化标记了@Component等注解的类为Bean,包括默认扫描规则及自定义扫描条件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 前言

在日常开发中,如果我们希望某些组件加入到 Spring 容器的管理中,肌肉记忆使我们很自然的在某些类上加入了@Component 注解,但是往往不明所以,因此我在这里简单记录一下

2. @Component 相关注解

  • @RestController
  • @Controller
  • @Service
  • @Repository
  • @Configuration
  • 其它

这些注解的元注解都存在 @Component,在这里我们统称存在 @Component 注解

3. 源码解析

3.1 ConfigurationClassParser#doProcessConfigurationClass

doProcessConfigurationClass 这个方法比较重要,以下注解都可以处理:

  • @ComponentScan
  • @ComponentScans
  • @Import
  • @ImportResource
  • @PropertySource
  • @PropertySources

有兴趣的小伙伴,可以阅读相关博文:Spring之ConfigurationClassPostProcessor解析流程

3.2 ComponentScanAnnotationParser#parse

3.3 ClassPathBeanDefinitionScanner 构造方法

默认情况下,如果配置类上存在 @ComponentScan 注解,则会构建一个 ClassPathBeanDefinitionScanner 对象,并且给其 includeFilters 属性赋值,includeFilters 明细如下:

  • new AnnotationTypeFilter(Component.class)
  • new AnnotationTypeFilter(ManagedBean.class):如果相关类存在
  • new AnnotationTypeFilter(Named.class):如果相关类存在

3.4 ClassPathBeanDefinitionScanner#doScan

由源码可以,如果 isCandidateComponent 方法返回 true,则会构建一个ScannedGenericBeanDefinition 对象,添加到候选者列表中。所以 metadataReader 对象只需要不满足 excludeFilters 的 match 方法,并且满足 includeFilters 的 match 方法,则表示这是一个候选者。

3.5 AnnotationTypeFilter#match

3.5.1 AnnotationTypeFilter 构造方法

根据上述源码, 相关属性值如下:

  • considerInherited : false
  • considerInterfaces : false
  • annotationType : Component.class
  • considerMetaAnnotations : true

主要调用父类(AbstractTypeHierarchyTraversingFilter)的 match 方法,流程图如下:

因为 considerInherited、considerInterfaces 值为 false,我们主要关注 AnnotationTypeFilter  的 matchSelf 方法

3.5.2 AnnotationTypeFilter#matchSelf

即对于 new AnnotationTypeFilter(Component.class) 这个 AnnotationTypeFilter,只要类上存在@Component 注解或者 @Component 注解的包装注解,都会返回true。所以默认情况下只要类上存在 @Component 注解都会被扫描、解析成一个 ScannedGenericBeanDefinition 对象,后期再根据 bean 的建模对象(BeanDefinition)实例化成 bean。@ManagedBean@Named 注解相关的 AnnotationTypeFilter 也是同理

4. 案例演示

4.1 类上存在 @ManagedBean 注解,最终被扫描成 Bean

4.1.1 创建实体类 NamedComponent
@ManagedBean
public class NamedComponent {
}
4.1.2 创建配置类 AppConfig
@ComponentScan("com.test.config")
public class AppConfig {
}
4.1.3 创建启动类 Main
public class Main {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

        NamedComponent bean = context.getBean(NamedComponent.class);
        System.out.println(bean);
    }
}
4.1.4 执行 main 方法

通过运行结果,得出结论:Spring 容器中存在类型为 NamedComponent 的 bean,即类上存在 @ManagedBean 注解,最终被扫描成 Bean

4.2 @ComponentScan 将存在自定义注解的 class 扫描、解析、实例化成 bean

4.2.1 创建自定义注解 TestComponent
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TestComponent {

}
4.2.2 创建实体类 MyComponent,类上标记自定义注解 @TestComponent
@TestComponent
public class MyComponent {
}
4.2.3 修改配置类 AppConfig
@ComponentScan(basePackages = "com.test.config",
        includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, value = TestComponent.class)})
public class AppConfig {

}
4.2.4 修改启动类
public class Main {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

        MyComponent myComponent = context.getBean(MyComponent.class);
        System.out.println(myComponent);

        NamedComponent bean = context.getBean(NamedComponent.class);
        System.out.println(bean);
    }
}
4.2.5 执行main方法

4.2.6 注意点 

如果 @ComponentScan 注解的 useDefaultFilters 属性为 false,即使类上存在 @Component@ManagedBean@Named 注解,也不会被扫描、解析、实例化成 bean

@ComponentScan(basePackages = "com.test.config",
        useDefaultFilters = false,
        includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, value = TestComponent.class)})
public class AppConfig {

}

5. 小结

  • 默认情况下,如果类上存在 @Component@ManagedBean@Named 注解,则会被@ComponentScan 注解被扫描、解析、实例化成 bean。
  • 如果 @ComponentScan 注解的 useDefaultFilters 属性为 false,即使类上存在 @Component@ManagedBean@Named 注解,也不会被扫描、解析、实例化成 bean
  • @ComponentScan 注解还可以自定义 includeFilters,只要 includeFilters 或 defaultFilters 存在一个filter 的 match 方法返回 true,相关类就会被扫描、解析、实例化成 bean
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值