Spring是怎么扫描这些Bean的

一、总览

这个问题问得非常棒!这就开始进入Spring的核心机制之一了:组件扫描(Component Scan)机制

✅ 一句话总结

Spring是通过包扫描(Component Scanning)的方式,在项目启动时自动找到标注了@Component、@Service、@Repository、@Controller等注解的类,并把它们注册为Bean,放进Spring容器中管理。

🔍 整体流程分 3 步走:

1️⃣ 开启组件扫描:告诉Spring去哪里找Bean

通常是在Spring Boot启动类XML配置里写:

👉 Spring Boot 示例:

@SpringBootApplication  // 内部包含 @ComponentScan
public class App {
    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }
}  

默认扫描启动类所在包及其子包下的所有类

你也可以显式指定扫描包路径:

@ComponentScan(basePackages = {"com.example.service", "com.example.dao"})

2️⃣ 使用注解标记要被扫描的类

Spring会识别这些注解,把类注册成Bean:

@Component

泛指组件(最基础的注解)

@Service

业务逻辑组件

@Repository

DAO 数据访问组件

@Controller

控制器,Web请求入口

这些其实都是@Component的"语义化子注解"

3️⃣ Spring 在启动时会做这些事:

在启动期间,Spring会:

  • 扫描你指定的包路径下的所有class文件
  • 找出被这些注解标记的类
  • 通过反射把它们实例化(使用构造器)
  • 把它们注册为Bean,放进Spring容器
  • 可以通过@Autowired或@Resource来自动注入它们

🧠 Spring 是怎么实现的?(原理底层)

组件扫描是由ClassPathBeanDefinitionScanner这个类完成的,它会:

  1. 根据你配置的base-package找到所有.class 文件
  2. 读取这些类的注解(基于反射 + ASM 字节码工具)
  3. 如果发现类上有@Component 或其子注解,就创建一个 BeanDefinition
  4. 把这些BeanDefinition注册到Spring的容器中

最终你调用ApplicationContext.getBean(...)或使用@Autowired就能拿到它。

🎯 小例子回顾

@ComponentScan(basePackages = "com.mycompany")
public class AppConfig {}

@Service
public class MyService {}

@RestController
public class MyController {
    @Autowired
    private MyService myService;
}

启动时会自动发现MyService,并把它注入到MyController中。

🧪 想验证扫描效果怎么办?

你可以在Spring Boot启动日志中搜索:

Creating shared instance of singleton bean 'myService'

或者开启Bean打印日志,看看你的类有没有被注册成功。

✅ 总结

1. 配置扫描路径

用 @ComponentScan或@SpringBootApplication

2. 加注解标记类

用@Component/@Service/@Controller等

3. 启动时扫描

Spring利用反射+ASM扫描并注册为Bean

4. 容器管理

可以用@Autowired自动注入了

二、只有这四种@Component、@Service、@Repository DAO 数据访问组件、@Controller会被SpringBoot识别并注册成Bean吗?是没有别的了吗?

你提到的那四种注解(@Component、@Service、@Repository、@Controller)确实是最常见的被SpringBoot自动扫描并注册成Bean的注解,但不是"只有这四种"。

接下来我给你详细拆解下:

1.这四个是最常见的"元注解"

@Component

通用组件

✅ 基础注解

@Service

业务逻辑层

是@Component的派生

@Repository

DAO 数据层

是@Component的派生

@Controller

控制器层

是@Component的派生

也就是说,它们本质上都是@Component的语义包装,所以SpringBoot能识别它们

2.还有这些注解,也会被注册为Bean!

1️⃣ @RestController

  • 是@Controller + @ResponseBody的组合,用于REST风格接口。
  • 也会被自动注册为Bean。

2️⃣ @Configuration

  • 表示这是一个配置类,Spring会把它注册为Bean。
  • 类似传统的 XML <beans> 配置。
@Configuration
public class AppConfig {}

3️⃣ @Bean

  • 用于手动注册Bean(不是自动扫描的方式)。
  • 放在 @Configuration 类中,表示方法返回值就是一个 Bean。
@Bean
public MyService myService() {
    return new MyService();
}

4️⃣ @ComponentScan

  • 它本身不是注册Bean的,而是用来指定哪些包路径需要被扫描。

3.自定义注解也可以

你甚至可以自定义一个注解,然后加上@Component元注解,让Spring也能扫描它

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface MyCustomComponent {
}

然后你可以像这样用:

@MyCustomComponent
public class MyHandler {}

Spring 也会把它识别成一个 Bean。

4.SpringBoot还有自动注册机制(自动装配)

除了扫描注解以外,SpringBoot 还有一些更高级的注册方式:

1. @EnableAutoConfiguration + SpringFactories

  • Spring Boot会从META-INF/spring.factories或META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports里找自动配置类。
  • 比如你引入了spring-boot-starter-web,就自动给你注册了DispatcherServlet、Tomcat、Jackson等Bean。

🎯 小结:除了你说的四个注解,还有这些也会注册为Bean

@Component

✅ 是

最基础的

@Service

✅ 是

业务层

@Repository

✅ 是

DAO 层

@Controller

✅ 是

控制器层

@RestController

✅ 是

REST 风格控制器

@Configuration

✅ 是

配置类

@Bean

✅ 手动注册

用在配置类方法上

自定义注解

✅(如果带@Component)

也能被扫描

自动配置类

Spring Boot 特有机制

三、所以所有带@符号的注解,都会在启动时被SpringBoot扫描到并注册成Bean对吗?

结论是:❌不是所有带@符号的注解都会被Spring Boot扫描并注册成Bean

✅ 先说重点答案

只有特定注解 + 特定位置 + 特定配置下的类,才会被Spring Boot扫描并注册成Bean。

❗那到底哪些注解会被注册成 Bean 呢?

只有那些本身标注了@Component间接标注了它的注解,Spring Boot才会识别并注册为Bean。

比如:

注解

本质是否是@Component?

能否自动注册为Bean

用途说明

@Component

通用组件

@Service

✅(是@Component的子注解)

业务逻辑层

@Repository

DAO 数据层

@Controller

控制器层

@RestController

✅(组合注解)

REST 控制器

@Configuration

✅(底层是@Component)

配置类

@Bean

✅(注册方法返回值)

配置类中的注册方式

@RequestMapping

/ @PostMapping

是功能注解,不是 Bean 注解

@Autowired

是注入工具,不是 Bean 定义

@Transactional

是切面功能,不注册 Bean

✅ Spring Boot是怎么判断一个类是不是Bean的?

Spring Boot的自动扫描器(ClassPathBeanDefinitionScanner)在扫描类时,只会找那些带有@Component或其派生注解的类

也就是说,SpringBoot 启动后:

  • 会扫描指定的包路径
  • 对每个类进行"注解判断"
  • 如果发现类上有@Component或它的派生注解就生成一个BeanDefinition注册进Spring 容器

其它的注解,比如@RequestMapping、@Autowired、@Getter(Lombok)、@Slf4j、@NotNull、@Override等,只是功能型注解,Spring并不会把这些类注册成Bean

🧠 举个反例说明

public class TestTool {
    @PostConstruct
    public void init() {
        System.out.println("init...");
    }
}

这个类没有加任何@Component或其子注解,它不会被Spring注册为Bean,即使它有很多带@的注解,比如@PostConstruct、@Slf4j、@Data,也没用。

✅ 想让一个类被注册为Bean,必须满足以下条件之一:

方式

说明

类上加了 @Component或其子注解

最推荐

被@Bean方法返回

用在配置类里注册第三方类

通过XML配置

传统方式,现在不常用了

被SpringBoot自动装配机制注册

如引入starter自动配置类

📌 总结回顾

说法

正确吗

原因

所有带@的注解都会让类变成 Bean?

❌ 错

只有@Component及其子注解才行

想让一个类被Spring容器管理,必须加啥?

✅ 加@Component或子注解,或用@Bean注册

@Autowired的类一定是Bean?

✅ 被注入的对象必须是Bean,使用注入的地方也必须是Bean

全部评论

相关推荐

评论
2
17
分享

创作者周榜

更多
牛客网
牛客企业服务