首页 > 其他分享 >编写一个自己的SpringBoot Starter

编写一个自己的SpringBoot Starter

时间:2023-10-30 09:03:33浏览次数:32  
标签:SpringBoot spring boot 编写 config public Starter

我们用SpringBoot的时候发现有很多starter,比如spring-boot-starter-web等,对于SpringBoot的官方starter,基本上是以spring-boot-starter-xxx来命名的,对于非官方的一些包来说,我们该怎样将自己的包与SpringBoot结合起来呢?在SpringBoot的官方文档中,有这样一章,Creating Your Own Starter,来教我们如何编写自己的starter。

理解@Conditional

我们可以控制一个类在满足某一条件才能进行实例化吗?
在Spring中有一个@Conditional注解和Condition接口,这个接口有一个matches方法,使用者可以重写这个方法,如下所示:

public class TestCondition implements Condition {

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        return true;
    }
}

然后我们就可以把@Conditional(value = TestCondition.class)标注在类上面,表示该类下面的所有@Bean都会启用配置,也可以标注在方法上面,只是对该方法启用配置。

spring-boot-autoconfigure中,SpringBoot官方实现了一系列Condition,用来方便平时的开发,这些实现类都位于org.springframework.boot.autoconfigure.condition,并且每个都提供了对应的注解,下面相关注解及其说明:

注解 说明
@ConditionalOnBean 在BeanFactory已经存在指定Bean
@ConditionalOnMissingBean 在BeanFactory不存在指定Bean
@ConditionalOnClass 在classpath下已存在指定class
@ConditionalOnMissingClass 在classpath下不存在指定class
@ConditionalOnCloudPlatform 指定的云平台已生效(Cloud Foundry platform,Heroku platform,SAP Cloud platform)
@ConditionalOnExpression 指定的SPEL表达式为true时
@ConditionalOnJava 指定的Java版本(前或者后)
@ConditionalOnJndi 指定的JNDI存在
@ConditionalOnNotWebApplication 非web应用
@ConditionalOnWebApplication web环境
@ConditionalOnProperty 指定的property有指定的值
@ConditionalOnResource 在classpath下存在指定的资源
@ConditionalOnSingleCandidate BeanFactory中该类型Bean只有一个或@Primary的只有一个时

基本原理

用过SPI机制的同学可能会清楚一个概念,当一个框架需要动态的扩展能力,给使用者给予充分的扩展能力,那么可能会用到SPI机制。在SpringBoot中,如果我们编写了一个Starter,SpringBoot框架怎么会识别我们的项目呢?所以我们就需要告诉SpringBoot,这里是我写的Starter,你运行时加载吧,类似SPI。SpringBoot正好提供了该功能,被称为Auto-configuration,下面是SpringBoot的官方文档:

Spring Boot checks for the presence of a META-INF/spring.factories file within your published jar. The file should list your configuration classes under the EnableAutoConfiguration key, as shown in the following example:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.mycorp.libx.autoconfigure.LibXAutoConfiguration,\
com.mycorp.libx.autoconfigure.LibXWebAutoConfiguration

从上面可以看出,只要我们在我们自己的Stater的META-INF/spring.factories中配置好AutoConfiguration,SpringBoot就可以检测到并且加载啦。这个AutoConfiguration需要用@Configuration标识,代表它是一个配置类,并且结合上面提到的@Conditional及其相关注解,灵活地读取相应配置信息。

实现步骤

SpringBoot官方推荐自定义Starter以xxx-spring-boot-starter命名,并且分两个模块,Autoconfigure模块Starter模块,主要配置在Autoconfigure模块Starter模块是一个空项目。首先在父项目的pom文件加入SpringBoot依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-dependencies</artifactId>
    <version>${spring-boot.version}</version>
    <type>pom</type>
    <scope>import</scope>
</dependency>

Autoconfigure模块

Autoconfigure模块加入如下依赖:

<!-- Compile dependencies -->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-autoconfigure</artifactId>
</dependency>

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

其中spring-boot-configuration-processor主要是用来生成元数据文件(META-INF/spring-configuration-metadata.json )。如果存在该文件,那么SpringBoot会优先读取该元数据文件,提高启动速度。

编写自定义Service

我们编写一个测试Service,其中config是从配置文件读取的:

public class StarterService {
    private String config;

    public StarterService(String config) {
        this.config = config;
    }

    public String[] split(String separatorChar) {
        return StringUtils.split(this.config, separatorChar);
    }
}

编写配置文件读取类

我们用SpringBoot时,会在application.yml中编写一些配置,如果我们要编写自己的配置,那么肯定要读取的,下面这个类用来读取配置文件信息:

@ConfigurationProperties("example.service")
public class StarterServiceProperties {
    private boolean enable;
    private String config;

    public boolean isEnable() {
        return enable;
    }

    public void setEnable(boolean enable) {
        this.enable = enable;
    }

    public String getConfig() {
        return config;
    }

    public void setConfig(String config) {
        this.config = config;
    }
}

编写AutoConfigure

接下来编写AutoConfigure文件。@ConditionalOnClass代表classpath 中有StarterService这个class,@EnableConfigurationProperties代表启用StarterServiceProperties这个配置类,@ConditionalOnMissingBean代表BeanFactory中没有StarterService这个Bean才实例化,@ConditionalOnProperty根据指定的配置文件指定的值来判断是否加载该Bean。代码如下:

@Configuration
@ConditionalOnClass(StarterService.class)
@EnableConfigurationProperties(StarterServiceProperties.class)
public class StarterAutoConfigure {

    @Autowired
    private StarterServiceProperties properties;

    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnProperty(prefix = "example.service", value = "enable", havingValue = "true")
    StarterService starterService () {
        return new StarterService(properties.getConfig());
    }

}

配置spring.factories

最后在META-INF文件夹新建spring.factories中加入如下配置:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=me.mingshan.spring.boot.autoconfigure.StarterAutoConfigure

如果有多个,以,隔开。

Starter模块

Starter模块是个空的项目,只有一个pom文件,加入如下依赖:

  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
      <groupId>me.mingshan</groupId>
      <artifactId>demo-spring-boot-autoconfigure</artifactId>
      <version>${project.version}</version>
    </dependency>
  </dependencies>

测试

新建一个测试项目,将stater依赖引入,在application.yml文件加入如下配置:

example:
  service:
    enable: true
    config: qqq,www

新建一个Runner,实现ApplicationRunner接口,当我们启动SpringBoot容器时,就会执行下面该类,输出qqq www

@Component
public class Runner implements ApplicationRunner {
    @Autowired
    private StarterService starterService;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        String[] splitArray = starterService.split(",");
        for (String str : splitArray) {
            System.out.println(str);
        }
    }
}

References:


title: 编写一个自己的SpringBoot Starter
tags: [java,SpringBoot]
author: Mingshan
categories: Java
date: 2019-6-26

标签:SpringBoot,spring,boot,编写,config,public,Starter
From: https://www.cnblogs.com/mingshan/p/17793496.html

相关文章

  • Springboot整合XXL-job
    1、开发步骤:pom.xml<!--xxl-job--><dependency><groupId>com.xuxueli</groupId><artifactId>xxl-job-core</artifactId><version>2.3.1</version></dep......
  • Springboot拦截器的使用
    1.拦截器(Interceptor)在SpringBoot中,拦截器是基于SpringMVC框架的一部分,主要用于对控制器方法进行拦截处理。拦截器是通过实现HandlerInterceptor接口来定义的其中包括三个主要方法:preHandle、postHandle和afterCompletion。1.preHandle方法在进入控制器方法之前执行2.postHan......
  • SpringBoot简介&IDEA在线创建一个SpringBoot项目
    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档文章目录前言一、pandas是什么?二、使用步骤1.引入库2.读入数据总结前言SpringBoot项目创建有三种方式,分别是在线创建、使用Springinitializr快速创建、和改造Maven工程创建,本期讲的就是如何在线创建一个SpringBoot项......
  • 基于SpringBoot框架的教学评价系统-计算机毕业设计源码+LW文档
    摘要随着时代的发展,我国的教育水平在不断的提高,但是很多时候为了更好的提高教学的质量,会让学生对当前的教学进行评价,教育工作者根据学生的评价发现当下教学中的一些不足,从而更好的提高教学质量,为了让教学评价变的更加的方便我们开发了本次的教学评价系统。本系统从用户的角度出......
  • SpringBoot 公司推广系统 公司广告系统
    SpringBoot公司推广系统公司广告系统系统功能首页功能:广告展示方案列表站内搜索资讯查看详细咨询登录注册收藏咨询方案在线客服实时聊天后台管理功能:系统管理分为:用户管理角色管理客户管理首页轮播管理公告管理方案管理:方案管理资讯管理:类型管理资讯......
  • 收藏从未停止,练习从未开始——MYSQL游标存储过程IDEA快捷键配置SpringBoot入门到入土G
    “收藏从未停止,练习从未开始”,或许有那么一些好题好方法,在被你选中收藏后却遗忘在收藏夹里积起了灰?今天请务必打开你沉甸甸的收藏重新回顾,分享一下那些曾让你拍案叫绝的好东西吧!本人详解:(提醒:随笔)本人详解作者:王文峰,参加过2020年度博客之星,《Java王大师王天师》作者采购供应链共享......
  • 【SpringBoot】Docker部署
    docker部署是主流的部署方式,极大的方便了开发部署环境,保持了环境的统一,也是实现自动化部署的前提。1项目的目录结构package:点击打包,生成xxx-SNAPSHOT.jartarget目录:打包生成目录,生成的jar存放位置Dockerfile:跟项目根目录同级2创建Dockerfile#Docker镜像构......
  • springboot+vue2+element学生信息管理系统
    效果:  .vue<template><div><el-containerstyle="height:700px;border:1pxsolid#eee"><el-headerstyle="font-size:40px;background-color:rgb(238,241,246)">学生管理</el-header&......
  • springboot 断点上传、续传、秒传实现
    前言springboot断点上传、续传、秒传实现。保存方式提供本地上传(单机)和minio上传(可集群)本文主要是后端实现方案,数据库持久化采用jpa一、实现思路前端生成文件md5,根据md5检查文件块上传进度或秒传需要上传分片的文件上传分片文件分片合并后上传服务器二、数据库表对象说明:Abs......
  • SpringBoot使用Redis分布式缓存
    Redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sortedset有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基......