手摸手教你学会自定义starter

139 阅读5分钟

本文记录快速实现自定义starter,过程中会跳过一些原理。建议了解一些springboot的自动装配原理再来食用效果更佳,当然了不了解也没关系。

有些小伙伴可能对于自定义starter有点陌生,其实大家在日常开发过程中或多或少接触过,比如我们常用的mybatis-plus,它就是一个官方制作的starter,它可以提供一些api和配置一些参数来方便我们调用。我们不用很在意为什么我们使用了这样的api就可以完成调用,帮我们屏蔽了一些细节。

我们大致了解了starter可以帮我们做什么了。可能也会有人说那么为什么不直接引入jar包呢?本篇章不做解释,小伙伴们可以使用文心一言来搜索一下,输入以下问题即可。

自定义starter与直接导入jar包有何区别?

让我们直接步入正题吧。首先打开idea,创建一个springboot项目,什么依赖都不需要勾选,直接创建。 创建好之后,删掉启动类和test文件夹,并添加一些依赖,如下

<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>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
<!--                打包出现没有mainClass异常解决方法-->
            <configuration>
                <skip>true</skip>
            </configuration>
        </plugin>
    </plugins>
</build>

全部的依赖,没有额外的依赖

此时我们假设一个很简单的需求,starter提供一些简单的api来返回我们配置在第三方的配置参数 只是用来演示并没有实际意义。

我们用来接收配置文件的实体类

@ConfigurationProperties(prefix = "auto-client")  // properties或者是yml文件中自定义的变量,以auto-client开头
public class AutoProperties {
    private String name;
    private String address;
    // 省略一些get set方法
}

starter提供的方法/服务

public class AutoService {
    @Resource
    private AutoProperties autoProperties;
    public String getName(){
        return autoProperties.getName();
    }
    public String getAddress(){
        return autoProperties.getAddress();
    }
}

配置类

@Configuration
@EnableConfigurationProperties(AutoProperties.class)
public class AutoConfig {
    @Bean
    public AutoService autoService(){
        return new AutoService();
    }
}

此时就有一个问题了,那么该如何使得别的项目依赖了该starter可以直接获取到AutoService并调用其中的api呢?那么此时就需要使用到springboot的自动装配的原理了。可能有的小伙伴并不是很清楚,建议先了解该原理,可以更好的理解。当然也可以看完本章内容之后,在进行了解。假如你不太了解,此时我们可以参考别人是如何写的,比如mybatis-plus,此时引入该依赖,可以看到 mybatis.png 当然了,如果移除掉该依赖,那么我们也能找到一些蛛丝马迹 image.png

此时我们需要在在上述提到的META-INF文件夹直接拷贝到我们的resources目录下,然后进行删减只保留 additional-spring-configuration-metadata.jsonspring.factories

image.png

additional-spring-configuration-metadata.json是用来提示的,我们在日常开发过程中估计都见过,只不过可能不太清楚。如图所示,大家是不是很熟悉,这个文件的作用就是这样的。接下来我们呢做一些简单的配置

image.png

{
  "properties": [
    {
      "name": "auto-client.name",   -- 配置文件的key
      "type": "java.lang.String",   -- 配置文件key后面接的数据是什么类型的
      "description" : "学生名称",    -- 描述是干什么用的
      "defaultValue": "大耳朵糊涂"   -- 默认值,就跟上面的8080一样
    },{
      "name": "auto-client.address",
      "type": "java.lang.String",
      "description" : "地址",
      "defaultValue": "苏州"
    }
  ]
}

spring.factories是用来自动导入的,如果有的小伙伴们不知道自动装配的话,可以自行了解哦,关键词springboot的自动装配 内容为

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.hu.config.AutoConfig    -- 自动装配的路径

此时我们就可以直接使用idea打包。点击test 然后点击图中2跳过test,然后双击install进行打包。此时我们就可以在我们的本地maven仓库中看到我们的jar包了,当然也可以在target目录查看到我们打成的jar包

image.png

image.png

此时我们还是相同的手法创建另一个springboot项目,还是什么依赖都不要勾选,直接完成。然后在pom文件中导入我们制作好的starter有的小伙伴们不知道如何导入,我教大家一个方法,直接拷贝如图红圈圈中的三行。

image.png 然后在我们的测试自定义starter pom文件中引入,然后刷新maven即可

image.png 此时我们就可以看到我们的starter被导入了我们的项目中了

image.png

接下来我们开始进行一些配置来完成我们的需求(调用starter来返回配置在properties文件中的值),此时就可以发现我们在starter中配置的提示已经起到了作用了

image.png

使用最简单的测试方法

@SpringBootApplication
public class TestStartDemoApplication {
    public static void main(String[] args) {
        ApplicationContext context = SpringApplication.run(TestStartDemoApplication.class, args);
        AutoService autoService = context.getBean(AutoService.class); // 因为我们的starter已经自动装配了,所以是可以获取到我们的bean的
        System.out.println(autoService.getAddress());
    }
}

此时小伙伴们就可以看到控制台打印出了我们的姓名了哦。小伙伴们学废了嘛。

本文到此结束,可能有些错误或者是描述不清楚的地方,希望大佬多多指点。


更新:在 Spring Boot 2.7.0 及以上版本中发生了一些变化,如下图所示(建议对比下图与低版本的截图,特别是关注 spring.factories 文件的内容)。我们会发现 org.springframework.boot.autoconfigure.EnableAutoConfiguration 这一行在旧版本中存在,但在新版本中被移除了。不过,高版本中多出来的一个文件名看起来非常类似这一行代码。

image.png

如果选择这种方式进行注入,只需在文件内容中明确写出所需注入类的全限定名即可轻松实现。值得注意的是,较高版本依然兼容这种较低版本的写法,但反过来则不成立。对此感兴趣的朋友们可以深入探索两种方法之间的差异;本文将不再赘述此部分内容。