spring-brick 为动态扩展系统而生的插件开发框架

背景

在当下后端市场,还是以spring-boot为核心框架进行系统开发,本框架可以在spring-boot系统上进行插件式的开发,将插件当做一个mini版本的spring-boot进行系统扩展开发,可以解决如下痛点:

  1. 在To-B系统场景中,不同甲方会有不同的需求,在不打分支和改动系统核心代码的前提下,可以在插件中进行扩展开发特定功能,不同甲方使用不同插件,完美解决非核心系统的扩展功能开发,例如扩展中台系统的不同需求。
  2. 在To-C系统场景中,可以在主程序通过定义java-interface,在插件中做不同实现,来达到动态扩展系统功能。
  3. 在开发中,由于引入了不同版本的依赖,导致系统无法运行,本框架可以完美解决在不同插件中定义不同版本的依赖,从底层进行隔离,以解决引入不同版本依赖冲突的问题。比如可以完美解决系统同时连接数据库mysql-5和mysql-8版本。
  4. 在开发中,不同插件依赖不同框架的功能,可以按需引入。比如在插件A引入连接mysql、在插件B引入连接elasticsearch、在插件C引入连接oracle。
  5. 在插件中,可以任意集成不同的非web类型的springboot-xx-starter,然后将不同插件功能组装起来,以达到一个统一对外提供服务的完整系统,实现系统组装化、插拔化开发
  6. 在不重启主程序的前提下,对插件进行动态的安装、卸载、启动、停止

介绍

该框架可以在spring-boot项目上开发出插件功能,在插件中可以和spring-boot使用方式一模一样。使用了本框架您可以实现如下需求:

  • 在插件中,您可以当成一个微型的spring-boot项目来开发,简单易用。
  • 在插件中扩展出系统各种功能点,用于系统灵活扩展,再也不用使用分支来交付不同需求的项目了。
  • 在插件中可以集成各种框架及其各种spring-boot-xxx-starter。
  • 在插件中可以定义独立依赖包了,再也不用在主程序中定义依赖包了。
  • 可以完美解决插件包与插件包、插件包与主程序因为同一框架的不同版本冲突问题了。各个插件可以定义同一依赖的不同版本框架。
  • 无需重启主程序,可以自由实现插件包的动态安装部署,来动态扩展系统的功能。
  • 插件也可以不依赖主程序独立集成微服务模块。
  • ~~~等等,您可以丰富想象该框架给您带来哪些迫切的需求和扩展,以实现系统的低耦合、高内聚、可扩展的优点。

特性

  1. 简化了框架的集成步骤,更容易上手。
  2. 插件开发更加贴近spring-boot原生开发。
  3. 支持两种模式开发: 隔离模式、共享模式, 可自主根据需要灵活选择使用。
  4. 使用Maven打包插件,支持对插件的自主打包编译。目前支持:
  • 开发打包:将插件打包成开发环境下的插件(仅需打包一次)。
  • 生产打包:将插件打包成一个jar、zip、文件夹等。
  1. 自主的开发的类加载器,支持插件定义各种的依赖jar包。
  2. 在插件中可以集成各种框架及其各种spring-boot-xxx-starter,比如集成mybatis、mybatis-plus、spring-jpa等。
  3. 动态安装、卸载、启动、停止插件。
  4. 主程序和插件类隔离, 有效避免主程序与插件、插件与插件之间的类冲突。

架构

主程序配置集成

1. 引入框架依赖


  com.gitee.starblues
  spring-brick
  ${latest.version}

2. 在配置文件加入配置

plugin:
  runMode: dev
  mainPackage: com.gitee.starblues.example
  pluginPath:
     - D://project//plugins(替换为自己环境下插件目录)
  • 配置说明:

runMode: 运行模式, 开发环境: dev; 生产环境: prod。dev环境下,只适用于在idea环境下开发调试,prod环境只能加载打包的插件,比如jar、zip等,插件打包详见: 插件打包详细说明

mainPackage: 主程序扫描的包名。

pluginPath: 插件目录或者插件上级目录,可配置多个。

  • 详细配置见:https://www.yuque.com/starblues/iuyk4y/pm8x4g

3. 改造 Spring-Boot 启动类

  • 在main类中实现框架引导类SpringBootstrap,在run方法中使用和SpringBoot启动方式一致的实现。
  • 在main方法中使用SpringMainBootstrap进行引导启动。具体实现如下:
import com.gitee.starblues.loader.launcher.SpringMainBootstrap;
import com.gitee.starblues.loader.launcher.SpringBootstrap;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application implements SpringBootstrap {

    public static void main(String[] args) {
        // 该处使用 SpringMainBootstrap 引导启动
        SpringMainBootstrap.launch(Application.class, args);
    }

    @Override
    public void run(String[] args) throws Exception {
        // 在该实现方法中, 和 SpringBoot 使用方式一致
        SpringApplication.run(Application.class, args);
    }
}

4. 打包主程序

  • 主程序使用maven命令:mvn clean install进行打包

插件配置集成

1. 引入依赖




  org.springframework.boot
  spring-boot-starter
  ${和主程序一致的springboot版本}




  com.gitee.starblues
  spring-brick-bootstrap
  ${latest.version}





  主程序的 groupId
  主程序的 artifactId
  主程序 version
  provided

2. 定义插件引导类


注意:插件包名不能和主程序包名一致,如需一致,需遵循:插件包名范围小于等于主程序包名。

详细规则可见:
https://www.yuque.com/starblues/spring-brick-3.0.0/siet7b


  • 定义插件main入口类, 继承SpringPluginBootstrap类, 然后在main函数中实例化当前引导类,并执行run方法即可。实现如下:
import com.gitee.starblues.bootstrap.SpringPluginBootstrap;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ExamplePlugin extends SpringPluginBootstrap {
    
    public static void main(String[] args) {
        new ExamplePlugin().run(args);
    }
    
}

3. 配置Maven打包插件

  • 使用框架自带的打包插件,对插件包进打包。
  • 将如下配置加入到插件的maven的 pom.xml 中

  
    
      com.gitee.starblues
      spring-brick-maven-packager
      ${latest.version}
      
        
        dev
        
        
          
          plugin-example
          
          com.gitee.starblues.example.ExamplePlugin
          
          1.0.0-SNAPSHOT
        
      
      
        
          
            repackage
          
        
      
    
  
  • 详细打包插件说明见: https://www.yuque.com/starblues/iuyk4y/tfxx2b

4. 新增 Controller 接口

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/example")
public class ExampleController {
    @GetMapping
    public String hello(){
        return "hello";
    }
}

5. 编译插件

  • 插件使用maven命令:mvn clean package进行编译

启动测试

  • 启动主程序main, 日志中出现如下关键内容,说明集成插件成功
c.g.s.i.operator.DefaultPluginOperator   : 插件加载环境: dev
c.g.s.core.PluginLauncherManager         : 插件[plugin-example@1.0.0-SNAPSHOT]加载成功
c.g.s.b.p.web.PluginControllerProcessor  : 插件[plugin-example]注册接口: {GET [/plugins/module1/example]}
c.g.s.core.PluginLauncherManager         : 插件[plugin-example@1.0.0-SNAPSHOT]启动成功
c.g.s.i.operator.DefaultPluginOperator   : 插件初始化完成
  • 打开浏览器,访问接口: http://127.0.0.1:8080/plugins/plugin-example/example 进行测试是否能访问成功。