Skip to content

Starter机制 ​

深入理解SpringBoot Starter的设计思想和实现机制,学会编写标准的Starter,掌握自动配置类、条件注解的使用,能够从零开始创建自定义Starter。

📋 Starter机制概览 ​

Starter是SpringBoot的核心机制之一,通过约定优于配置的思想,简化依赖管理和配置。

🎯 一、Starter设计理念 ​

1.1 约定优于配置 ​

SpringBoot Starter遵循"约定优于配置"的思想:

  • 零配置:引入Starter即可使用,无需额外配置
  • 默认配置:提供合理的默认配置
  • 可覆盖:允许用户通过配置文件覆盖默认配置

1.2 Starter命名规范 ​

官方Starter命名:

  • 格式:spring-boot-starter-{name}
  • 示例:spring-boot-starter-web、spring-boot-starter-data-jpa

第三方Starter命名:

  • 格式:{name}-spring-boot-starter
  • 示例:mybatis-spring-boot-starter、druid-spring-boot-starter

🎯 二、标准Starter结构 ​

2.1 Starter项目结构 ​

标准Starter项目结构:

my-custom-starter/
├── pom.xml
├── src/
│   ├── main/
│   │   ├── java/
│   │   │   └── com/example/
│   │   │       ├── autoconfigure/
│   │   │       │   ├── MyServiceAutoConfiguration.java
│   │   │       │   └── MyServiceProperties.java
│   │   │       └── service/
│   │   │           └── MyService.java
│   │   └── resources/
│   │       └── META-INF/
│   │           └── spring.factories
│   └── test/
│       └── java/
│           └── com/example/
│               └── autoconfigure/
│                   └── MyServiceAutoConfigurationTest.java

2.2 pom.xml配置 ​

Starter的pom.xml:

xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
    <modelVersion>4.0.0</modelVersion>
    
    <groupId>com.example</groupId>
    <artifactId>my-custom-starter</artifactId>
    <version>1.0.0</version>
    <packaging>jar</packaging>
    
    <name>My Custom Starter</name>
    <description>My custom Spring Boot Starter</description>
    
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.0</version>
        <relativePath/>
    </parent>
    
    <properties>
        <java.version>17</java.version>
    </properties>
    
    <dependencies>
        <!-- Spring Boot Starter -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        
        <!-- Spring Boot Configuration Processor -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        
        <!-- 其他依赖 -->
    </dependencies>
</project>

🎯 三、自动配置类编写 ​

3.1 自动配置类结构 ​

标准自动配置类:

java
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(MyService.class)
@ConditionalOnProperty(prefix = "my.service", name = "enabled", 
        havingValue = "true", matchIfMissing = true)
@EnableConfigurationProperties(MyServiceProperties.class)
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
public class MyServiceAutoConfiguration {
    
    @Bean
    @ConditionalOnMissingBean
    public MyService myService(MyServiceProperties properties) {
        return new MyService(properties);
    }
    
    @Bean
    @ConditionalOnClass(MyServiceAspect.class)
    @ConditionalOnProperty(prefix = "my.service", name = "aspect.enabled", 
            havingValue = "true", matchIfMissing = false)
    public MyServiceAspect myServiceAspect() {
        return new MyServiceAspect();
    }
}

关键注解说明:

  • @Configuration:标识为配置类
  • @ConditionalOnClass:当类路径存在指定类时生效
  • @ConditionalOnProperty:当配置属性满足条件时生效
  • @EnableConfigurationProperties:启用配置属性绑定
  • @AutoConfigureAfter:指定在某个配置类之后执行
  • @ConditionalOnMissingBean:当容器中不存在指定Bean时创建

3.2 配置属性类 ​

配置属性类定义:

java
@ConfigurationProperties(prefix = "my.service")
public class MyServiceProperties {
    
    /**
     * 服务名称
     */
    private String name = "default-service";
    
    /**
     * 服务地址
     */
    private String url = "http://localhost:8080";
    
    /**
     * 连接超时时间(毫秒)
     */
    private int connectTimeout = 5000;
    
    /**
     * 读取超时时间(毫秒)
     */
    private int readTimeout = 10000;
    
    /**
     * 是否启用
     */
    private boolean enabled = true;
    
    // getters and setters
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    // ... 其他getter/setter
}

配置属性元数据(可选):

src/main/resources/META-INF/spring-configuration-metadata.json:

json
{
  "properties": [
    {
      "name": "my.service.name",
      "type": "java.lang.String",
      "description": "服务名称",
      "defaultValue": "default-service"
    },
    {
      "name": "my.service.url",
      "type": "java.lang.String",
      "description": "服务地址",
      "defaultValue": "http://localhost:8080"
    },
    {
      "name": "my.service.connect-timeout",
      "type": "java.lang.Integer",
      "description": "连接超时时间(毫秒)",
      "defaultValue": 5000
    },
    {
      "name": "my.service.enabled",
      "type": "java.lang.Boolean",
      "description": "是否启用服务",
      "defaultValue": true
    }
  ]
}

🎯 四、注册自动配置类 ​

4.1 spring.factories文件 ​

在spring.factories中注册:

src/main/resources/META-INF/spring.factories:

properties
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.autoconfigure.MyServiceAutoConfiguration

4.2 新版方式(Spring Boot 2.7+) ​

使用spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports:

src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports:

com.example.autoconfigure.MyServiceAutoConfiguration

🎯 五、完整的Starter示例 ​

5.1 业务服务类 ​

java
public class MyService {
    
    private final MyServiceProperties properties;
    
    public MyService(MyServiceProperties properties) {
        this.properties = properties;
    }
    
    public String doSomething(String input) {
        // 使用配置属性
        String url = properties.getUrl();
        int timeout = properties.getConnectTimeout();
        
        // 执行业务逻辑
        return "Processed: " + input + " via " + url;
    }
    
    public String getName() {
        return properties.getName();
    }
}

5.2 自动配置类 ​

java
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(MyService.class)
@ConditionalOnProperty(prefix = "my.service", name = "enabled", 
        havingValue = "true", matchIfMissing = true)
@EnableConfigurationProperties(MyServiceProperties.class)
public class MyServiceAutoConfiguration {
    
    private final MyServiceProperties properties;
    
    public MyServiceAutoConfiguration(MyServiceProperties properties) {
        this.properties = properties;
    }
    
    @Bean
    @ConditionalOnMissingBean
    public MyService myService() {
        return new MyService(properties);
    }
    
    @Bean
    @ConditionalOnProperty(prefix = "my.service", name = "monitor.enabled", 
            havingValue = "true", matchIfMissing = false)
    public MyServiceMonitor myServiceMonitor(MyService myService) {
        return new MyServiceMonitor(myService);
    }
}

5.3 使用示例 ​

引入Starter:

xml
<dependency>
    <groupId>com.example</groupId>
    <artifactId>my-custom-starter</artifactId>
    <version>1.0.0</version>
</dependency>

配置文件:

yaml
# application.yml
my:
  service:
    enabled: true
    name: my-custom-service
    url: http://api.example.com
    connect-timeout: 5000
    read-timeout: 10000
    monitor:
      enabled: true

使用服务:

java
@RestController
public class MyController {
    
    @Autowired
    private MyService myService;
    
    @GetMapping("/test")
    public String test() {
        return myService.doSomething("test");
    }
}

🎯 六、Starter最佳实践 ​

6.1 设计原则 ​

原则1:单一职责

一个Starter只负责一个功能模块,避免功能过于复杂。

原则2:零配置可用

提供合理的默认配置,用户无需配置即可使用。

原则3:配置可覆盖

允许用户通过配置文件覆盖默认配置。

原则4:条件判断

使用条件注解,只在满足条件时才创建Bean。

6.2 命名规范 ​

  • 包名:使用autoconfigure作为自动配置类的包名
  • 类名:使用{Name}AutoConfiguration作为自动配置类名
  • 属性类:使用{Name}Properties作为配置属性类名

6.3 测试 ​

自动配置测试:

java
@SpringBootTest
class MyServiceAutoConfigurationTest {
    
    @Autowired(required = false)
    private MyService myService;
    
    @Test
    void testMyServiceAutoConfiguration() {
        assertThat(myService).isNotNull();
        assertThat(myService.getName()).isEqualTo("my-custom-service");
    }
    
    @Test
    @SpringBootApplication
    static class TestConfiguration {
    }
}

📖 学习资源 ​

视频教程 ​

书籍推荐 ​

  • 《Spring Boot实战》 - 汪云飞
  • 《Spring Boot 2精髓》 - 李家智

网站资源 ​

✅ 学习检查清单 ​

  • [ ] 已理解Starter的设计理念
  • [ ] 已掌握标准Starter的项目结构
  • [ ] 已学会编写自动配置类
  • [ ] 已学会编写配置属性类
  • [ ] 已理解spring.factories的作用
  • [ ] 已掌握条件注解的使用
  • [ ] 已能够创建自定义Starter

上一章节:自动配置原理
下一章节:条件注解机制
返回目录:SpringBoot源码深度解析