Spring boot 自定义starter

150 阅读3分钟

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

前言

spring boot对开发者非常的友好,因为Spring官方提供了很多的stater,这些是stater都是工作中常用的一些组件,它屏蔽掉了开发者整合其他组件的时候因为依赖版本冲突带来的问题。

基于这种特性,开发者也可以在团队内部通过开stater来为其他项目或其他项目提供基本服务。

今天通过参考开源的mybatis提供的mybatis-spring-boot-starter的编写方式,开发出一个属于自己的stater。

创建启动器模块

创建启动项目myapp-spring-boot-starter。由于启动器不需要代码实现,只需要依赖其他项目,所以直接创建一个空的maven项目即可,但是名字要规范。

image.png

在创建的pom.xml文件中引入接下来要创建的myapp-spring-boot-autoconfigure项目

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.xinxin.spring.boot</groupId>
    <artifactId>myapp-spring-boot-starter</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>com.xinxin.spring.boot</groupId>
            <artifactId>myapp-spring-boot-autoconfigure</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
    </dependencies>
</project>

创建自动配置项目

创建myapp-spring-boot-autoconfigure项目,项目中引入springboot父项目以及spring-boot-starter

image.png

pom.xml配置文件。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.11.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.xinxin.spring.boot</groupId>
    <artifactId>myapp-spring-boot-autoconfigure</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>myapp-spring-boot-autoconfigure</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>

</project>

属性绑定类

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

/**
 * 自动绑定配置属性值类
 */
@ConfigurationProperties(prefix = "myapp.hello")
public class HelloProperties {

    private String suffix;

    public String getSuffix() {
        return suffix;
    }

    public void setSuffix(String suffix) {
        this.suffix = suffix;
    }
}

服务提供类

/**
 * 业务处理类
 */
public class HelloService {

    private HelloProperties helloProperties;

    public HelloService(HelloProperties helloProperties) {
        this.helloProperties = helloProperties;
    }

    public String sayHello(String name) {
        return "Hello " + name + "," + helloProperties.getSuffix();
    }

}

自动配置类

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

/**
 * 自动配置类
 */
@ConditionalOnWebApplication
@ConditionalOnClass(HelloService.class)
@EnableConfigurationProperties(HelloProperties.class)
@Configuration
public class HelloServiceAutoConfiguration {

    @Autowired
    private HelloProperties helloProperties;

    @Bean
    @ConditionalOnProperty(prefix = "myapp",value = "enabled",havingValue = "true")
    public HelloService helloService(){
        HelloService helloService = new HelloService(helloProperties);
        return helloService;
    }
}

配置文件

  • 在resource目录下新建文件目录META-INF

  • 在META-INF目录下新建springboot项目启动要扫描的加载的文件spring.factories

  • spring.factories指定springboot项目启动要自动装配的类

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.xinxin.spring.boot.autoconfigure.HelloServiceAutoConfiguration

注解解释

@ConditionalOnWebApplication 是web项目情况下进行自动配置 @ConditionalOnClass 当classpath下发现该类的情况下进行自动配置 @ConditionalOnProperty(prefix = "myapp",value = "enabled",havingValue = "true")当配置文件中myapp.enabled=true时 进行自动装配

常见@Conditional

  • @ConditionalOnBean:当容器中有指定的Bean的条件下

  • @ConditionalOnClass:当类路径下有指定的类的条件下

  • @ConditionalOnExpression:基于SpEL表达式作为判断条件

  • @ConditionalOnJava:基于JVM版本作为判断条件

  • @ConditionalOnJndi:在JNDI存在的条件下查找指定的位置

  • @ConditionalOnMissingBean:当容器中没有指定Bean的情况下

  • @ConditionalOnMissingClass:当类路径下没有指定的类的条件下

  • @ConditionalOnNotWebApplication:当前项目不是Web项目的条件下

  • @ConditionalOnProperty:指定的属性是否有指定的值

  • @ConditionalOnResource:类路径下是否有指定的资源

  • @ConditionalOnSingleCandidate:当指定的Bean在容器中只有一个,或者在有多个Bean的情况下,用来指定首选的Bean

  • @ConditionalOnWebApplication:当前项目是Web项目的条件下

安装

在 myapp-spring-boot-autoconfigure项目执行 mvn install 把自动配置项目打包到本地仓库,然后使用相同的命令把 myapp-spring-boot-starter 安装到仓库。因为后者依赖于前者项目,所以这里前者需要先进 mvn install。

image.png

步骤总结

  1. 创建名字为xxx-spring-boot-starter的启动项目

  2. 创建名字为xxx-spring-boot-autoconfigure的项目

  • 编写属性绑定类xxxProperties

  • 编写服务类xxxService,引入xxxProperties

  • 编写自动配置类xxxAutoConfiguration

  • 创建MAT-INF/spring.factories文件,用于指定要自动配置的类

  1. 启动器项目为空项目,用来引入xxx-spring-boot-autoconfigure等其他依赖

  2. 项目引入自定义的xxx-spring-boot-starter,配置需要配置的信息