Spring Boot 作为 Java 开发领域的核心框架,通过其“约定优于配置”的理念,极大地简化了应用的初始搭建与开发过程。其中,自动装配机制允许开发者通过简单的依赖引入,即可将复杂的 Bean 对象自动注入到 IoC 容器中,显著减少了样板代码,让开发者能更专注于业务逻辑的实现。本文将深入剖析这一机制的运作原理,并通过一个完整的示例,演示如何从零开始手写一个可复用的自定义 Starter 组件。
自动装配原理剖析
理解 Spring Boot 自动装配,首先需要了解 Java 的 SPI(Service Provider Interface)机制。其核心流程可以概括为以下几个关键步骤:
- 启动入口:Spring Boot 应用启动时,会扫描主类上的
@SpringBootApplication 复合注解。
- 核心注解:
@SpringBootApplication 注解内部包含了 @EnableAutoConfiguration 注解,这是激活自动配置功能的关键。
- 导入选择器:
@EnableAutoConfiguration 注解通过 @Import 导入了 AutoConfigurationImportSelector 类。该类的主要职责是执行 selectImports 方法。
- 加载配置:
selectImports 方法并非凭空创造配置,而是基于 SPI 机制,去项目 classpath 下所有 META-INF/spring.factories 文件中,查找 org.springframework.boot.autoconfigure.EnableAutoConfiguration 配置项对应的值。
- 注册 Bean:这些配置项的值是一个个自动配置类(标注了
@Configuration)的全限定名。Spring Boot 会加载这些配置类,并根据其中的条件注解(如 @ConditionalOnClass)判断是否生效。生效的配置类中定义的 @Bean 方法,其返回的对象就会被自动注册到 Spring IoC 容器中。
整个过程的“自动”之处在于,开发者无需显式地在自己的代码中使用 @Configuration 和 @Bean 来声明这些组件,只需引入相应的 Starter 依赖,符合条件后便会自动完成装配。
为了更直观地理解,我们可以查看官方 Starter 的结构。例如,在项目的依赖库中打开 mybatis-spring-boot-autoconfigure-2.2.2.jar 包,其 META-INF 目录下就存在一个 spring.factories 文件,其核心内容通常如下所示:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.mybatis.spring.boot.autoconfigure.MybatisLanguageDriverAutoConfiguration,\
org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration
而官方提供的 Starter(如 spring-boot-starter-web),其自动配置类则直接定义在 spring-boot-autoconfigure-2.6.11.jar 包的 META-INF/spring.factories 文件中,其中定义了大量的 ApplicationContextInitializer、ApplicationListener 和 AutoConfigurationImportFilter 等,构成了完整的自动配置体系。
手写一个自定义 Starter 实战
理解了原理,我们通过一个简单的示例来实践如何创建一个自定义 Starter。我们将创建一个名为 “boy-starter” 的组件,它能够根据配置自动向容器中注入一个 Boy 对象。
第一步:创建 Starter 项目
首先,我们创建一个标准的 Maven 项目,注意,不需要 application.properties 和 Application 主启动类。项目的核心目录结构如下所示:
demo
├── .idea
├── src
│ ├── main
│ │ ├── java
│ │ │ └── com
│ │ │ └── sc
│ │ │ └── demo
│ │ │ ├── Boy.java
│ │ │ ├── BoyAutoConfiguration.java
│ │ │ └── BoyProperties.java
│ │ └── resources
│ │ └── META-INF
│ │ ├── additional-spring-configuration-metadata.json
│ │ └── spring.factories
│ └── test
└── .gitignore
第二步:定义核心业务类
我们创建一个简单的 Boy 类,它有一个 say() 方法。
/**
* @author suncong
*/
public class Boy{
public static Boy create(String name){
return new Boy(name);
}
private String name;
public Boy(String name){
this.name = name;
}
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
public String say(){
return name+",Hello World!";
}
}
第三步:创建自动配置类
这是 Starter 的核心,它决定了在什么条件下创建 Boy Bean。
/**
* @author suncong
*/
@ConditionalOnClass(Boy.class) // 当类路径下存在 Boy 类时,此配置类才生效
@EnableConfigurationProperties(BoyProperties.class) // 启用配置属性类
@Configuration
@Data
@ComponentScan
public class BoyAutoConfiguration{
/**
* 将对象交给IOC管理
* @param boyProperties
* @return
*/
@Bean
Boy boy(BoyProperties boyProperties){
return new Boy(boyProperties.getName());
}
}
第四步:定义配置属性类
该类负责从使用方的配置文件中读取属性。
/**
* @author suncong
*/
@ConfigurationProperties(prefix = "demo.boy")
public class BoyProperties{
private String name;
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
}
这是实现自动装配的“钥匙”,必须正确创建。
-
spring.factories (必须)
在 src/main/resources/META-INF/ 下创建此文件,内容指定我们的自动配置类。
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.sc.demo.BoyAutoConfiguration
注意:路径和文件名必须完全正确,常见的错误有拼写为 META_INF 或 spring.factoies。
-
additional-spring-configuration-metadata.json (可选)
此文件用于为 IDE 提供配置项的元数据提示(如类型、描述、默认值),提升开发体验。
{
"properties": [
{
"name": "demo.boy.name",
"type": "java.lang.String",
"description": "想跳舞的人",
"defaultValue": "sc"
}
]
}
第六步:打包安装
在 IDE 的 Maven 工具窗口中,依次执行 clean 和 install 命令,将我们编写的 Starter 项目打包并安装到本地 Maven 仓库。成功执行后,其他本地项目就可以像引用其他依赖一样引用这个自定义 Starter 了。
第七步:测试使用 Starter
现在,我们新建一个普通的 Spring Boot 应用来测试这个 Starter。
-
添加依赖:在 pom.xml 中引入我们刚刚创建的 Starter。
<dependency>
<groupId>com.sc</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
-
编写主应用:创建一个简单的 Web 控制器,并自动注入 Boy 对象。
/**
* @author SunCong
*/
@RestController
@SpringBootApplication
public class Demo1Application{
public static void main(String[] args){
SpringApplication.run(Demo1Application.class, args);
}
@Autowired
private com.sc.demo.Boy boy;
@GetMapping("/say")
public String say(){
return boy.say();
}
}
-
配置文件:在 application.properties 中配置 Boy 的名称。
server.port=8081
demo.boy.name="scscsc"
-
启动与测试:
启动应用,控制台会输出标准的 Spring Boot 启动日志,包括 “Tomcat started on port(s): 8081 (http)” 等信息,表明应用启动成功。
打开浏览器访问 localhost:8081/say,页面将显示:“scscsc, Hello World!”。
修改配置文件中的 demo.boy.name 值为 "shuaige" 并重启应用,再次访问,页面将显示:“shuaige, Hello World!”。
至此,一个功能完整的自定义 Spring Boot Starter 就开发并验证成功了。
官方 Starter 与第三方 Starter 的区别
在日常开发中,我们可能会注意到两种命名风格的 Starter,例如:
spring-boot-starter-web (官方)
mybatis-spring-boot-starter (第三方)
它们的主要区别在于:
- 命名规范:官方的 Starter 通常遵循
spring-boot-starter-{功能模块} 的命名方式;而第三方 Starter 则通常使用 {模块名}-spring-boot-starter 的格式。
- 自动配置类的位置:这是最关键的技术区别。
- 第三方 Starter(如 MyBatis)的自动配置类定义在其自身 JAR 包的
META-INF/spring.factories 文件中。
- 官方提供的 Starter(如 Web、JPA 等)的自动配置类,是集中定义在
spring-boot-autoconfigure 这个独立 JAR 包的 META-INF/spring.factories 文件中的。这个文件里包含了 ApplicationContextInitializer、ApplicationListener、AutoConfigurationImportFilter 以及海量的 EnableAutoConfiguration 配置项,构成了 Spring Boot 自动配置的基石。
掌握 Spring Boot 自动装配的原理并能够自定义 Starter,是深入理解 Spring Boot 生态和构建可复用微服务架构组件的重要一步。它不仅能帮助开发者更好地使用现有框架,也为封装团队内部技术资产、统一技术栈提供了强大的工具。
参考资料
[1] SpringBoot自动装配原理+手写一个starter组件, 微信公众号:mp.weixin.qq.com/s/F_9Ux9LjuJ_h7oCr7fL9Zw
版权声明:本文由 云栈社区 整理发布,版权归原作者所有。