# sakura-springboot-plugin
**Repository Path**: Cutie_Sakura/sakura-springboot-plugin
## Basic Information
- **Project Name**: sakura-springboot-plugin
- **Description**: 自定义的gradle插件,可将SpringBoot 项目扩展支持插件化开发.
- **Primary Language**: Java
- **License**: LGPL-3.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 12
- **Forks**: 2
- **Created**: 2021-07-13
- **Last Updated**: 2024-09-30
## Categories & Tags
**Categories**: spring-boot-ext
**Tags**: SpringBoot, gradle插件, 插件化开发
## README
# 工程简介
将speingboot项目扩展改造成支持插件化开发的Gradle插件项目.
可使项目运行时,动态加载指定目录下的jar包到依赖内,
实现插件化开发效果.
有点类似lib依赖外置的感觉, 启动后自动加载指定目录内的jar包为依赖.
有的同学可能尝试过,将某些插件jar直接通过压缩工具放入xxx.jar类的lib内,启动后放入的jar不会被加载,
或者外置lib的项目,将插件jar放入外置的lib文件内,启动后放入的jar也不会被加载.
通过本插件工具,即可实现,在不改动原始xxx.jar 的情况下,启动xxx.jar时,自动加载加指定目录的插件.
---
更多配置参数,详见控制台
## 特点功能
* 与原生ide内多模块开发依赖一致,无差异,效果相同,
* 方便快捷,一次添加,终身受益
* 插件配置式插拔于springboot项目。
* 在springboot上可以进行插件式开发, 扩展性极强, 可以针对不同项目开发不同插件, 进行不同插件jar包的部署。
* 在插件应用模块上可以使用Spring注解定义组件, 进行依赖注入。
* 支持在插件中开发Rest接口。
* 支持在插件中单独定义持久层访问等需求。
* 可以遵循主程序提供的插件接口开发任意扩展功能。
* 支持注解进行任意业务场景扩展, 并使用定义的坐标进行场景命中。
* 支持自定义扩展开发接口, 使用者可以在预留接口上扩展额外功能。
* 支持插件之间的通信。
* 支持插件接口文档: Swagger、SpringDoc。
* 插件支持拦截器的定制开发。
### 可配参数
|名称|默认值|说明|自定义参数|
|:---:|:---:|:---:|:---:|
custom|false|是否开启自定义模式|×
springBootLoaderJarPath|null|SpringBoot启动器jar包路径|开启自定义后必填项
compileDir|project.getBuildDir();|编译路径|×
cacheDir|new File(compileDir, "libs")|缓存路径|×
cacheName|"sakuraCache"|缓存目录|×
buildDir|new File(compileDir, "libs")|构建目录|×
buildJarName|project.getName() + "-" + project.getVersion()|构建jar名称|×
myLauncherName|"MyLauncher"|启动器类名|√
myLauncherPackageName|"com.sakura.hk.plugin"|启动器包名|√
pluginPathProperty|"sakura.plugin.path"|从JVM获取插件所在径路的属性名|√
pluginPathProperty|"sakura.plugin.name"|从JVM获取插件所在文件夹名称的属性名|√
pluginPathName|"myPlugin"|默认插件所在文件夹名称|√
suffix|"sakura"|生成jar包的后缀|×
delCache|true|是否删除缓存文件|×
type|SakuraBootType.JAR|打包类型|×
### 参数详细说明
> 自定义模式参数即为必须开启自定义模式配置才生效的参数
> * × 更改后无需开启自定义模式即可生效
> * √ 更改后需要开启自定义模式才剩下
* **custom** 指示是否开启自定义模式
- true 开启
- false 关闭(默认值)
* **springBootLoaderJarPath** SpringBoot启动器jar包路径
开启自定义模式后必填,涉及到java代码的动态编译,需要依赖,
及当前Springboot项目所使用的spring-boot-loader包的硬盘路径,如没有可前往mavne下载
,或在项目中依赖`compileOnly 'org.springframework.boot:spring-boot-loader'` 后刷新项目,gradle会自动下载依赖
,随后前往`.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-loader\`目录下查找与项目使用Springboot版本相同的jar包路径
默认值: null
* **compileDir** 编译路径
项目编译路径,在gradle项目中,默认为根目录下build目录,一般情况下不需更改.
默认值为:project.getBuildDir()
插件默认自动获取当前项目Build目录
* **cacheDir** 缓存路径
插件工作时缓存文件存放路径,
默认值: new File(compileDir, "libs")
即为编译路径下的libs目录,
* **cacheName** 缓存目录
插件工作时,所有缓存文件均存放于缓存路径下的 缓存目录文件下
默认值: "sakuraCache"
`缓存路径`下的`sakuraCache`目录
* **buildDir** 构建路径
可理解为Springboot插件执行bootJar任务后生成jar包的路径,
默认值: new File(compileDir, "libs")
即为编译路径下的libs目录,
* **buildJarName** 构建jar的名称
可理解为Springboot插件执行bootJar任务后生成jar包的名称,
默认值 : project.getName() + "-" + project.getVersion()
即为当前 项目名称-项目版本, 如在bootJar 配置中更改jar名称或添加jar后缀,许手动更改此项
* **myLauncherName** 启动器类名
插件生成的启动类的类名
默认值: "MyLauncher"
* **myLauncherPackageName** 启动器类包名(包路径)
插件生成的启动类的包名
默认值: "com.sakura.hk.plugin"
* **pluginPathProperty** 从JVM获取插件所在径路的属性名
插件所在的路径,即为启动jar的时候 添加`-Dsakura.plugin.path` 定义插件所在的路径,
如 `System.getProperty("sakura.plugin.path")` 获取为null的时候,
使用`System.getProperty("user.dir")`获取当前启动路径
默认值 : "sakura.plugin.path"
* **pluginPathProperty** 从JVM获取插件所在文件夹名称的属性名
插件所在的路径下具体的文件夹名,即为启动jar的时候 添加`-Dsakura.plugin.name` 定义插件所在的文件夹,
如 `System.getProperty("sakura.plugin.name")` 获取为null的时候,
将使用 **pluginPathName** 参数 作为插件所在文件名
默认值 : "sakura.plugin.name"
* **pluginPathName** 默认插件所在文件夹名称
不开启自定义模式更改无效,可在启动jar的时候 添加`-Dsakura.plugin.name` 指定插件所在文件夹,
当`System.getProperty("sakura.plugin.name")` 获取为null的时候 使用默认值
默认值: "myPlugin"
* **suffix** 生成jar包的后缀
插件任务生成的jar包后缀,用来和Springboot生成的jar包区分
默认值: "sakura"
* **delCache** 是否删除缓存文件
运行插件任务后,是否删除插件工作时候产生的缓存文件
- true 开启(默认值)
- false 关闭
* **type** 打包类型
选择是jar包还是War包
- tSakuraBootType.JAR (默认值)
- faSakuraBootType.WAR (可能存在bug,推荐使用JAR)
### 任务详细说明
* **akuraInit** 初始化准备任务
打印显示了当前插件工作的各种参数
* **decompressionSpringbootBuild** 解压springboot生成的jar包
解压缩Springboot构建,输出到缓存目录
* **generateMyMainClassFile** 生成启动类
生成启动主类编译文件,并存在与指定位置
* **setSpringbootStartupMainClass** 更改springboot指定的启动类
将springboot指定的启动类更改为 `generateMyMainClassFile` 任务生成的启动类
* **generateNewBuildJar** 生成新的jar包
生成被sakrua插件定制化后的jar包
* **clearCache** 是否删除缓存文件
将sakrua插件工作时产生的缓存文件清理
* **sakuraPlugInBuild** 调用sakura插件编译项目
插件工作的入口,类似bootJar任务,以前打包执行`bootJar`,现在打包执行`sakuraPlugInBuild`
## 示例
示例位于根目录**Examples**内
### 定义
* **api** 接口模块,定义了一些接口
* **main-progeam** 主程序,集成api模块,需要调用实现类
* **plus-in** api接口的实现
### 实现
**api** 模块定义 `ISample`接口,代码如下
```java
package com.sakura.hk.examples;
/**
* 一个样品示例
*
* @Author: sakura
* @Date: 2021/7/19
*/
public interface ISample {
public void getName();
public void getId();
}
```
**plus-in** 模块实现 api接口,并使用Spring的相关方式进行bean注册
* 使用@Bean 注册ASample
代码去下所示
``` java
package com.sakura.hk.examples;
/**
* @Author: Sakura
* @Date: 2021/7/19
*/
public class ASample implements ISample {
private String id = "A:001";
private String name =" 我是@Bean注册的,我当小弟吧";
@Override
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
@Override
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "ASample{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
'}';
}
}
//*******************************************************************************
package com.sakura.hk.examples;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @Author: Sakura
* @Date: 2021/7/19
*/
@Configuration
public class Config {
@Bean
public ISample aSample() {
return new ASample();
}
}
```
* 使用@Component 注册BSample
代码去下所示
```java
package com.sakura.hk.examples;
import org.springframework.stereotype.Component;
/**
* @Author: Sakura
* @Date: 2021/7/19
*/
@Component
public class BSample implements ISample {
private String id = "B:001";
private String name ="我是@Component注册的,我想当老大";
@Override
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
@Override
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "ASample{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
'}';
}
}
```
* **main-progeam** 主程序,集成api模块,需要调用实现类
其中`build.gradle` 配置了本示例的插件
实现CSample,作为示例,通过**Exhibition** 展示获取的Bean ,示例实现代码如下
```java
package com.sakura.hk.examples.main.progeam;
import com.sakura.hk.examples.ISample;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.List;
/**
* @Author: Sakura
* @Date: 2021/7/19
*/
@Component
public class Exhibition {
@Autowired
private List sampleList;
@PostConstruct
public void start() {
System.out.println(sampleList);
}
}
```
### 运行效果
```
PS C:\sakura\sakura-springboot-plugin\Examples\main-progeam\build\libs> java -jar .\main-progeam-0.0.1-SNAPSHOT-sakura.jar
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.3.7.RELEASE)
2021-07-19 23:11:51.800 INFO 8504 --- [ main] c.s.h.e.m.p.MainProgeamApplication : Starting MainProgeamApplication on DESKTOP-RDKKTNL with PID 8504 (C:\sakura\sakura-springboot-plugin\Examples\main-progeam\build\libs\main-progeam-0.0.1-SNAPSHOT-sakura.jar started by Sakura in C:\sakura\sakura-springboot-plugin\Examples\main-progeam\build\libs)
2021-07-19 23:11:51.803 INFO 8504 --- [ main] c.s.h.e.m.p.MainProgeamApplication : No active profile set, falling back to default profiles: default
[ASample{id='C:001', name='我是主程序提供的,我是老大'}, ASample{id='B:001', name='我是@Component注册的,我想当老大'}, ASample{id='A:001', name='我是@Bean注册的,我当小弟吧'}]
2021-07-19 23:11:52.479 INFO 8504 --- [ main] c.s.h.e.m.p.MainProgeamApplication : Started MainProgeamApplication in 1.249 seconds (JVM running for 3.487)
PS C:\sakura\sakura-springboot-plugin\Examples\main-progeam\build\libs>
```
# 常见问题
## 版本号说明
* 首位,大版本,通常指功能或框架大变动
* 中间,小版本,通常指功能更新
* 末尾,修复版本,通常为bug修订
## 快速上手
拉取项目编译或下载编译好的jar,
改动 **build.gradle** 文件内容,
以申请提交gradle官方仓库,等待审批中
* 引入依赖
```groovy
buildscript {
repositories {
// 本地仓库或指定目录
mavenLocal()
}
dependencies {
// 添加依赖
// 指定加载某路径下jar为依赖示例
// compile fileTree(dir:'../lib',includes:['*jar'])
// classpath fileTree(dir:'lib/sakura-springboot-plugin-0.1.1.jar')
classpath 'com.sakura.hk:sakura-springboot-plugin:Latest Version'
}
}
// 引入插件
apply plugin: 'sakrua.springboot.plugin'
```
* 启动gradle Tasks任务列表下 **sakuraSptingBoot** 分组内的 **sakuraPlugInBuild** 任务,即可完成打包.
* 打包完成后,默认识别运行目录下 myPlugin 文件下的jar为插件
# 贡献者们
主项目的贡献者们和 生态周边项目 的作者们:
sakrua
感谢大家的贡献。
# 规划功能
* ~~不开启自定义模式下,动态识别指定插件目录~~
* 识别多目录
* 定制插件过滤规则
* 编写高大上的说明文档 ==>> 40%
* 准备一个LOGO
* ~~编辑示例~~
* 编辑插件原理说明
* 加个license检查,防止通过注入插件破坏原项目内的license检测机制
# 插件原理讲解
// TODO 下次更新
## 我要赞赏
如果你喜欢帮助到了你,可以点右上角 ⭐Star 支持一下,谢谢 ^_^
# 技术交流
如果有什么问题或建议可以 ISSUE交流技术,分享经验。
QQ群: 15392541