自定义实现Spring Boot Stater

项目创建

这里我们引入parent以及redis的依赖

 <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
                <version>2.7.17</version>
        <relativePath/>
    </parent>
    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <spring.boot.version>2.7.17</spring.boot.version>
    </properties>
    <groupId>com.siyi</groupId>
    <artifactId>demo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
            <version>${spring.boot.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-redis</artifactId>
            <version>${spring.boot.version}</version>
        </dependency>

    </dependencies>

了解starter

pring Boot 对比 Spring MVC 最大的优点就是使用简单,约定大于配置。Starter主要目的是为了简化Spring应用的配置和初始化流程,帮助开发者减少项目搭建的复杂度和提高开发效率。

例如: 我们现在使用第三方的jar包,只需要三步

  1. 在 pom 文件中引入对应的包
  2. 在peroperties或者yml中加入相应的配置(有时不需要,根据官方文档)
  3. 依赖注入,使用

starter命名:

  • 官方的 starter 的命名格式为:spring-boot-starter-xxx
  • 非官方的 starter 的命名格式为:xxx-spring-boot-starter

实现自定义starter

实现一个starter有四点:

  1. starter 命名
  2. 自动配置类,用于自动创建bean,并交给spring容器
  3. 自动配置类需要的配置文件 spring.factories
  4. 业务类 (参考redisTemplete类)

导入依赖

作为依赖包, 这里需要导入两个依赖

  • spring-boot-autoconfigure:依赖包含了Spring Boot的自动配置逻辑,对于编写自定义自动配置类是必需的。如果你在创建一个自动配置模块或使用@ConditionalOnClass@ConditionalOnProperty等条件注解,这个库是必须的。
  • spring-boot-configuration-processor:这个依赖用于在编译时处理@ConfigurationProperties注解,它可以帮助生成元数据信息,这些信息能够提供给IDE,用于自动补全和校验配置属性。虽然这个依赖对于运行时不是必需的,但它在开发过程中非常有用,可以提高开发效率和减少配置错误。

完成配置实体类

这里的实体类可以有无其实都可以,也可以使用不依赖实体类的业务类,演示起见,这里使用实体类

@Data
@ConfigurationProperties(prefix = "siyi.address")
public class Myproperty {
    private String host;
    private int port;
}

这里**@ConfigurationProperties**如果爆红,可以考虑加上prefix=,这里的含义是绑定配置文件

yml:

siyi:
 address:
  host: 127.0.0.1
  port: 8090

完成业务类

@Data
public class BusinessService {
    private String host;
    private int port;
    public BusinessService(Myproperty myproperty){
        this.host = myproperty.getHost();
        this.port = myproperty.getPort();
    }
    public void print(){
        System.out.println(this.host + ":" +this.port);
    }
}

完成自动装配的类

这里最重要的注解是**@Configuration,自动装配会扫描这个注解,以及其@Bean注解**

@Configuration
@ConditionalOnClass(BusinessService.class)
@EnableConfigurationProperties(Myproperty.class)
public class MyAutoConfigure {
    @Autowired
    private Myproperty myproperty;
    @Bean
//    @ConditionalOnMissingBean(MyService.class)
    @ConditionalOnProperty(prefix = "siyi.address",value = "enabled", havingValue = "true",matchIfMissing = true)
    BusinessService businessService (){
        return new BusinessService(myproperty);
    }
}

另外两个注解意义是:

  • @ConditionalOnClass(BusinessService.class)
    • 这个注解指示 Spring Boot 自动配置类只有在 classpath 中存在指定的类(例如 BusinessService.class)时才会生效。换句话说,只有当项目的依赖中包含了 BusinessService 类时,才会应用这个自动配置类。
    • 这个注解通常用于根据类的存在与否来决定是否启用某些特定功能或配置,以避免在特定类不存在的情况下导致不必要的自动配置。
  • EnableConfigurationProperties(Myproperty.class)
    • 这个注解用于启用一个特定的配置类(例如 Myproperty.class),让其成为可配置的属性类。(这里如果不使用这个注解,会无法自动装配Myproperty)
    • 在 Spring Boot 中,@ConfigurationProperties 注解通常与这个注解一起使用,用于将外部配置文件中的属性绑定到特定的 Java 类上。当你使用 @EnableConfigurationProperties 注解时,Spring Boot 会自动注册这个配置类,以便可以在应用程序中使用这些配置属性。
    • 这样做的好处是,你可以通过在属性类中定义与配置文件中属性相对应的字段,然后通过 Spring Boot 自动绑定机制将配置文件中的值注入到这些字段中。

@ConditionalOnProperty 注解是 Spring Boot 提供的一种条件注解,它允许根据特定的环境属性来控制某个配置类或 bean 的创建。这个注解的属性如下所述:

  • prefix: 指定要检查的属性的前缀。在你的例子中,prefix = "siyi.address" 意味着将会检查所有以 siyi.address 为前缀的属性。
  • value: 指定具体的属性名(不包括前缀),这个属性的值会被检查。在你的例子中,value = "enabled" 意味着将会检查 siyi.address.enabled 这个具体的属性。
  • havingValue: 期望的属性值。只有当属性的实际值与 havingValue 指定的值相匹配时,相应的配置或 bean 才会被创建。在你的例子中,havingValue = "true" 指示只有当 siyi.address.enabled 的值为 true 时,条件才满足。
  • matchIfMissing: 这个属性表示如果指定的属性不存在时,是否应该满足条件。matchIfMissing = true 意味着如果 siyi.address.enabled 这个属性没有在配置中明确设置,条件仍然视为满足,从而导致配置或 bean 被创建。

完成配置文件

首先项目结构为:

image-20240306184101965

配置:

第一行是指示 Spring Boot 的自动配置机制,告诉它在启动时应该考虑哪些自动配置类。

第二行是你的自动装配类的全限定类名

corg.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.siyi.starter.configuration.MyAutoConfigure

打包

依次maven运行:

  1. clean
  2. install

测试

新建项目导入依赖进行测试,刚才我打的包为

 <dependency>
            <groupId>com.siyi</groupId>
            <artifactId>demo</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

全部pom

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.17</version>
        <relativePath/>
    </parent>
    <groupId>com.siyi</groupId>
    <artifactId>test</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
        /
        <dependency>
            <groupId>com.siyi</groupId>
            <artifactId>demo</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
         <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
    </dependencies>

写一个控制器测试,这里使用单元测试也可以

@RestController
@RequestMapping()
public class Test {
    @Autowired
    private BusinessService businessService;
    
@GetMapping("/")
    void tess() {
    businessService.print();
    }

}

运行结果:

image-20240306184632264

参考文献

  1. SpringBoot简介及手写个starter_手写starter springboot-CSDN博客
  2. 手写spring-boot-starter(一学就会系列)_手写springboot starter-CSDN博客