SpringBoot-自定义starter

270 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第3天,点击查看活动详情

如何自定义 starter

SpringBoot 的核心就是自动配置, 而支持自动配置的是一个个 starter 项目. 除了官方已有的starter, 用户也可以根据规则自定义自己的 starter 项目.

实现一个 starter 有四个要素:

  • starter 命名,需要遵守一定规范.
  • 自动配置类, 用来初始化相关的 bean.
  • 指明自动配置类的配置文件 spring.factories.
  • 自定义属性实体类, 声明 starter 的应用配置属性.

starter 的命名规范

starter 的名字,也就是在 pom 中引用的 artifactId. 命名是有规则的, 官方规定:

  • 官方的 starter 的命名格式为 spring-boot-starter-{name} , 如:spring-boot-starter-actuator.
  • 非官方的 starter 的命名格式为 {name}-spring-boot-starter

创建maven项目, 并填写 starter 的名字:

    <groupId>it.com</groupId>
    <artifactId>msg-spring-boot-starter</artifactId>
    <packaging>jar</packaging>
    <version>1.0-SNAPSHOT</version>

自定义 starter

短信发送是个很常见的功能,并且本身独立,使用的地方也比较多,完全可以独立出去,作为 starter 使用。

这个自定义的 starter 的源码地址 : msg-spring-boot-starter

最终结构如下:

① 引入 SpringBoot 自动化配置依赖 :

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-autoconfigure</artifactId>
    <version>2.0.3.RELEASE</version>
</dependency>

除此之外, 根据需要, 可以引入其他依赖.

② 定义 Service 服务类

定义 Service 服务类, 有两个作用, 一个为引入的项目本身的功能服务, 另外一个用来 Springboot 自动配置时的判断依据. 该服务类和 xxxTemplate 类似的功能.

这里定义一个 MsgService 的类.

@Data
public class MsgService {

    // 访问发送短信的url地址
    private String url;
    // 短信服务商提供的请求keyId
    private String accessKeyId;
    // 短信服务商提供的KeySecret
    private String accessKeySecret;

    public MsgService(String url, String accessKeyId, String accessKeySecret) {
        this.url = url;
        this.accessKeyId = accessKeyId;
        this.accessKeySecret = accessKeySecret;
    }

    public int sendMsg(String msg) {
        // 调用http服务并发送消息, 返回结果
        return HttpClientUtils.sendMsg(url, accessKeyId, accessKeySecret, msg);
    }
}

其中 MsgService 用到了一个自定义工具类 HttpClientUtils. 在 HttpClientUtils 中只是简单打印了请求的参数信息. 并没有实际发出请求. HttpClientUtils

③ 定义配置类

定义 MsgProperties 配置类, 用于封装 application.properties 或 application.yml 中的基础配置. 这里关于短信发送的配置前缀统一采用 msg. MsgProperties

通过 @ConfigurationProperties 注解来进行对应的属性的装配.

@Data
@ConfigurationProperties(prefix = "msg")
public class MsgProperties {

    // 访问发送短信的url地址
    private String url;
    // 短信服务商提供的请求keyId
    private String accessKeyId;

    // 短信服务商提供的KeySecret
    private String accessKeySecret;
}

④ 创建自动化配置类

自动配置类就是一个普通的 Java 类, 通过不同的注解来对其赋予不同的功能. 其中最核心的当然是 @Configuration 注解. MsgAutoConfiguration

@Configuration
@ConditionalOnClass(MsgService.class)
@EnableConfigurationProperties(MsgProperties.class)
public class MsgAutoConfiguration {

    //注入属性配置类
    @Resource
    private MsgProperties msgProperties;

    @Bean
    @ConditionalOnMissingBean(MsgService.class)
    @ConditionalOnProperty(prefix = "msg", value = "enabled", havingValue = "true")
    public MsgService msgService() {
        MsgService msgService = new MsgService(msgProperties.getUrl(),
                msgProperties.getAccessKeyId(),
                msgProperties.getAccessKeySecret());
        // 如果提供了其他set方法, 在此也可以调用对应方法对其进行相应的设置或初始化.
        System.out.println(msgService);
        return msgService;
    }
}

MsgAutoConfiguration 类上的注解 :

  • 注解 @Configuration 用来声明该类为一个配置类.

  • 注解 @ConditionalOnClass 说明只有当 MsgService 类存在于 classpath 中时才会进行相应的实例化

  • 注解 @EnableConfigurationProperties 会将 application.properties 中对应的属性配置设置到 MsgProperties 对象中.

msgService 方法上的注解 :

  • 注解 @Bean 表明该方法实例化的对象会被加载到容器当中

  • 注解 @ConditionalOnMissingBean 表示当容器中不存在 MsgService 的对象时, 再进行实例化.

  • 注解 @ConditionalOnProperty 表示当配置文件中 msg.enabled=true 时才进行相应的实例化.

⑤ 添加 spring.factories

resource/META-INF 目录下创建名称为 spring.factories 的文件, 对其进行注册.

在 spring.factories 配置文件中注册 MsgAutoConfiguration 类. 如果有多个自动配置类, 用逗号分隔换行即可.

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
it.com.config.MsgAutoConfiguration

⑥ 至此, 一个基于 Spring Boot 的自动配置 starter 便完成了.

打包安装

starter 编写完成之后, clean -> package -> install 安装到本地 maven 仓库. 方便其他项目中引用使用.

在其他项目中使用

在其他项目中, 引入该 自定义 starter 依赖.

<dependency>
    <groupId>it.com</groupId>
    <artifactId>msg-spring-boot-starter</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>

并配置需要的参数:

msg:
  enabled: true
  url: 127.0.0.1
  accessKeyId: 10001
  accessKeySecret: afelwjfwfwef

测试使用 :

@RestController
public class HelloWorldController {

    @Resource
    private MsgService msgService;	// 自定义的 starter 中的 service

    @RequestMapping("/sendMsg")
    public String sendMsg(){
        msgService.sendMsg("测试消息");
        return "ok";
    }
}

自定义 Starter 之 oss

自定义一个 oss-spring-boot-starter 文件上传的 Starter. oss-spring-boot-starter

  • 注解 @ConditionalOnWebApplication 表示当 Spring 为 web 服务时, 才使注解的类生效.

使用 :

oss:
  config:
    enable: true
    endpoint: 
    access-key-id: 
    access-key-secret: 
    bucket-name: 
    dir: blog/

其他优秀的 Starter

【源码】Starter 的工作流程

大概流程:

  • Spring Boot 在启动时扫描项目所依赖的 JAR 包, 寻找包含 spring.factories 文件的 JAR 包.

  • 根据 spring.factories 配置加载 AutoConfiguration 类.

  • 根据 @Conditional 注解的条件, 进行自动配置并将 Bean 注入 Spring 容器.

具体细节:

todo