一个注解启动整个项目?@SpringBootApplication 到底做了什么?
一个注解启动整个项目?@SpringBootApplication 到底做了什么?
刚接触 SpringBoot 的时候,我一直觉得这玩意很神奇。
以前启动 Spring 项目:
<context:component-scan/>
<bean/>
<bean/>
<bean/>
各种配置写一堆。
后来接触 SpringBoot。
发现启动类就这么几行:
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class,args);
}
}
项目居然就启动了。
第一次看到的时候我特别疑惑:
这个注解到底干了什么?
为什么删掉它项目直接启动失败?
为什么只加一个注解就能扫描 Bean、加载配置、自动配置各种组件?
今天我们就把它拆开看看。
先说结论
很多人以为:
@SpringBootApplication
是一个超级注解。
其实不是。
点进去你会发现:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan
public @interface SpringBootApplication {
}
看到这里是不是突然没那么神秘了。
它本质上就是:
三个注解的组合
第一个:@ComponentScan
这个大家最熟。
它负责扫描 Bean。
例如:
@Service
public class UserService {
}
@RestController
public class UserController {
}
Spring 为什么能发现它们?
因为:
@ComponentScan
启动时会扫描当前包以及子包。
然后把这些类注册到容器。
如果把它去掉:
@SpringBootApplication
改成:
@SpringBootConfiguration
@EnableAutoConfiguration
你会发现:
Controller 不见了
Service 不见了
Repository 不见了
因为根本没人扫描它们。
第二个:@SpringBootConfiguration
继续点进去:
@Configuration
public @interface SpringBootConfiguration {
}
是不是很眼熟?
实际上就是:
@Configuration
的一个包装。
什么意思?
告诉 Spring:
当前类是配置类
例如:
@Bean
public UserService userService() {
return new UserService();
}
Spring 就会把它注册成 Bean。
所以:
@SpringBootConfiguration
其实没有什么黑科技。
就是:
把启动类变成配置类
第三个:@EnableAutoConfiguration
真正厉害的来了。
很多人以为:
@SpringBootApplication
最核心的是扫描。
其实不是。
真正的灵魂是:
@EnableAutoConfiguration
因为自动配置全靠它。
什么叫自动配置
举个例子。
项目里引入:
mybatis-spring-boot-starter
什么都不写。
居然就能直接:
@Mapper
public interface UserMapper {
}
正常工作。
再引入:
spring-boot-starter-data-redis
RedisTemplate 又自动出现了。
很多人会觉得:
SpringBoot 好智能
但问题来了。
它怎么知道你想创建这些 Bean?
Debug 一下就明白了
断点打到:
SpringApplication.run()
一路跟进去。
最终会进入:
@EnableAutoConfiguration
然后继续进入:
AutoConfigurationImportSelector
看到这里很多人第一次懵。
名字很长。
其实翻译过来就一句话:
自动配置导入选择器
它负责决定:
哪些配置要加载
哪些配置不要加载
SpringBoot 真正干的事情
很多人觉得:
SpringBoot 会自动创建 Bean
其实不准确。
更准确地说:
SpringBoot 自动导入配置类
例如:
RedisAutoConfiguration
DataSourceAutoConfiguration
WebMvcAutoConfiguration
这些配置类里面本来就写好了:
@Bean
SpringBoot 只是帮你导进来。
然后 Spring 再正常创建 Bean。
所以流程其实是:
SpringBoot
↓
导入配置类
↓
Spring
↓
创建 Bean
为什么引入依赖就能生效
到这里很多人会发现新的问题。
既然自动配置这么厉害。
那它怎么知道:
RedisAutoConfiguration
在哪?
DataSourceAutoConfiguration
又在哪?
答案就在 Starter 里面。
每个 Starter 都提前声明好了:
我有哪些自动配置类
启动时 SpringBoot 全部读取。
然后根据条件决定是否加载。
所以:
引入 Starter
↓
发现自动配置类
↓
判断条件
↓
注册 Bean
这就是自动配置的核心流程。
为什么说 SpringBoot 最大的贡献不是自动配置
很多人学到这里会觉得:
SpringBoot = 自动配置
其实只说对了一半。
更准确的说:
SpringBoot = 自动配置 + 条件装配
因为它不会无脑创建 Bean。
例如:
项目里没有 Redis 依赖。
RedisAutoConfiguration
不会加载。
项目里没有 MySQL 驱动。
DataSourceAutoConfiguration
不会加载。
这就是 SpringBoot 强大的地方。
现在再看启动类
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class,args);
}
}
实际上它做了三件事:
扫描 Bean
把启动类变成配置类
开启自动配置
其中最重要的就是:
@EnableAutoConfiguration
没有它。
SpringBoot 自动配置体系基本就没了。
看到这里。
你应该已经明白:
@SpringBootApplication
并不是什么神秘黑科技。
它只是把:
@ComponentScan
@Configuration
@EnableAutoConfiguration
组合到了一起。
真正让 SpringBoot 变得强大的。
是背后的自动配置机制。
上一篇:
《SpringBoot 到底帮 Spring 自动做了什么?为什么突然不用写 XML 了?》
下一篇:
《为什么引入一个 Starter 就能自动生效?SpringBoot 自动配置原理》
评论区聊聊:
你有没有想过:为什么只引入一个 Starter,项目就突然多出了一堆 Bean?
更多推荐

所有评论(0)