前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >手把手教你自定义Spring Boot Starter

手把手教你自定义Spring Boot Starter

作者头像
李鸿坤
发布2020-08-13 16:05:12
7340
发布2020-08-13 16:05:12
举报
文章被收录于专栏:泛泛聊后端

官方提供的Spring Boot Starter涵盖面非常广,几乎所有流行的组件和方案都可以找到对应的封装。不过每个系统总会有自己的公共代码,可以自己进行Starter的封装。

下面以一个例子进行说明,我们需要一个HelloService的功能,但是又不想自己进行很多复杂的声明或者配置(实际应用场景中,远比HelloService的自动配置复杂得多)

代码语言:javascript
复制
package com.lihongkun.labs.spring.boot.hello;

public class HelloService {

    private String msg;

    public void sayHello(){
        System.out.println("hello " + msg);
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }
}
工程结构

创建一个Spring Boot Starter的工程,目录结构如下图,包含一个父工程,一个自动配置工程和Starter工程。

父工程

父工程只有一个pom文件,定义了Spring Boot 的版本依赖、编译的目标版本以及本项目的子模块。

代码语言:javascript
复制
<groupId>com.lihongkun.labs.spring.boot</groupId>
<artifactId>hello-spring-boot-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>

<modules>
  <module>hello-spring-boot-autoconfigure</module>
  <module>hello-spring-boot-starter</module>
</modules>
<packaging>pom</packaging>

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-dependencies</artifactId>
      <version>2.3.2.RELEASE</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>

<build>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-compiler-plugin</artifactId>
      <version>3.8.0</version>
      <configuration>
        <release>11</release>
      </configuration>
    </plugin>
  </plugins>
</build>
自动配置

接着创建autoconfigure工程,它会引入比较多的依赖,非必要的依赖使用optional的方式来引入。

代码语言:javascript
复制
<parent>
  <artifactId>hello-spring-boot-parent</artifactId>
  <groupId>com.lihongkun.labs.spring.boot</groupId>
  <version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>hello-spring-boot-autoconfigure</artifactId>

<dependencies>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-autoconfigure</artifactId>
  </dependency>
  <!--
    如果是实现 autoconfiguration 功能的依赖包一定要使用<optional>true</optional>
    因为你会在本工程里面定义多个不同功能的 autoconfiguration,引入方可能只使用了一个。
    如
    <dependency>
      <groupId>x.y.z</groupId>
      <artifactId>hey</artifactId>
      <version>0.0.1-SNAPSHOT<version>
      <optional>true</optional>
    </dependency>
    <dependency>
      <groupId>x.y.z</groupId>
      <artifactId>hello</artifactId>
      <version>0.0.1-SNAPSHOT<version>
      <optional>true</optional>
    </dependency>
   -->
</dependencies>

当我们的AutoConfiguration需要依赖一些外部配置的时候,比如数据库的配置或者当前的HelloService它需要一个msg,那么我们就可以创建一个Configuration的Properties对象,为其定义一个前缀。当被启用的时候,容器托管的配置即自动创建并填充到其ConfigurationProperties对象中。

代码语言:javascript
复制
package com.lihongkun.labs.spring.boot.hello;

import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties(prefix = HelloProperties.HELLO_PREFIX)
public class HelloProperties {

    public static final String HELLO_PREFIX = "hello";

    private String msg;

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }
}

不同的功能分在不同的AutoConfiguration实现,此处我们实现一个HelloAutoConfiguration,主要用来声明一个HelloService的Bean,这个Bean是条件创建的,也就是你引入后。如果觉得需要自己自定义,可以进行覆盖。HelloAutoConfiguration使用一个注解修饰EnableConfigurationProperties,这个注解的意思即当本类被实例化的时候则启用HelloProperties,创建一个HelloProperties的bean并填充配置值到其中。

代码语言:javascript
复制
package com.lihongkun.labs.spring.boot.hello;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableConfigurationProperties(HelloProperties.class)
public class HelloAutoConfiguration {

    @Autowired
    private HelloProperties helloProperties;

    @Bean
    @ConditionalOnMissingBean
    public HelloService helloService() {
        HelloService helloService = new HelloService();
        helloService.setMsg(helloProperties.getMsg());
        return helloService;
    }
}

准备就绪后,还需要一个重要的步骤。META-INF/spring.factories把HelloAutoConfiguration配置进去。格式如下

代码语言:javascript
复制
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.lihongkun.labs.spring.boot.hello.HelloAutoConfiguration
定义Starter

这是一个简单的pom工程,主要用来引入本Starter所需要的依赖,因为autoconfigure工程的optional依赖需要在这里正式引入。

代码语言:javascript
复制
<parent>
  <artifactId>hello-spring-boot-parent</artifactId>
  <groupId>com.lihongkun.labs.spring.boot</groupId>
  <version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>hello-spring-boot-starter</artifactId>
<packaging>pom</packaging>

<dependencies>
  <dependency>
    <artifactId>hello-spring-boot-autoconfigure</artifactId>
    <groupId>com.lihongkun.labs.spring.boot</groupId>
    <version>0.0.1-SNAPSHOT</version>
  </dependency>
  <!--
    本Starter依赖的包,在 autoconfigure 中 引入方式 optional,故此处需要再引入
    <dependency>
      <groupId>x.y.z</groupId>
      <artifactId>hello</artifactId>
    </dependency>
  -->
</dependencies>
使用

自定义工程本地install或者deploy到仓库中就可以直接进行使用了。

代码语言:javascript
复制
<groupId>com.lihongkun.labs</groupId>
<artifactId>hello</artifactId>
<version>1.0-SNAPSHOT</version>

<dependencies>
  <dependency>
    <groupId>com.lihongkun.labs.spring.boot</groupId>
    <artifactId>hello-spring-boot-starter</artifactId>
    <version>0.0.1-SNAPSHOT</version>
  </dependency>
</dependencies>

<build>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-compiler-plugin</artifactId>
      <version>3.8.0</version>
      <configuration>
        <release>11</release>
      </configuration>
    </plugin>
  </plugins>
</build>

package com.lihongkun.labs;

// Application.java
import com.lihongkun.labs.spring.boot.hello.HelloService;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        ApplicationContext context = SpringApplication.run(Application.class,args);
        HelloService helloService = context.getBean(HelloService.class);
        helloService.sayHello();
    }
}

//application.properties
hello.msg=spring boot stater

// 运行结果
hello spring boot stater
如果不想他自动生效的化可以设置为被动生效,比如增加EnableXXX注解来生效。相应的,你的AutoConfiguration需要增加ConditionalOn相关的条件注解。
小结

官方推荐自定义的Starter的命名方式是[custom]-spring-boot-starter,把功能寓意的名字放在前面。

工程结构官方也是有推荐的方式,一般公共的功能和自动化配置均放在一个autoconfigure项目中,此项目中除了定义自动化配置的一些AutoConfiguration外,在引入对应依赖的时候均使用optional的方式。原因是这么多功能并不知道使用者需要使用哪一个。

接着定义各个功能的Starter,这类项目中没有java源代码,而是指定功能的依赖,也就是上面用optional所引入的依赖,Spring Boot 使用了很多 ConditionalOn 注解来实现条件加载。比如ConditionalOnClass表示你的classpath下有某个类的字节码才进行自动配置。一旦你引入了某功能的Starter则autoconfigure的AutoConfiguration自动生效。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-08-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 泛泛聊后端 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 工程结构
  • 父工程
  • 自动配置
  • 定义Starter
  • 使用
  • 如果不想他自动生效的化可以设置为被动生效,比如增加EnableXXX注解来生效。相应的,你的AutoConfiguration需要增加ConditionalOn相关的条件注解。
  • 小结
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档