Spring Boot 可插件化拓展改造器,让 Spring-Boot 应用支持加载外部 jar 包,实现插件化拓展。
GitHub: https://github.com/core-lib/slot-maven-plugin
Spring-Boot 项目打包后是一个FatJar 即把所有依赖的第三方jar也打包进自身的jar中,运行时 classpath 包括 FatJar 中的 BOOT-INF/classes 目录和 BOOT-INF/lib 目录下的所有jar。
那么问题是要想加载外部化 jar 就只能打包期间把 jar 依赖进去,无法实现可插拔式插件化拓展。
Slot 就是一个可以将 Spring-Boot 项目升级为可支持加载外部 jar 的 Maven 插件。
一个 Spring-Boot JAR 启动的流程可以分为以下几步:
通过 java -jar spring-boot-app.jar args... 命令启动
JVM 读取该 jar 的 META-INF/MANIFEST.MF 文件中的 Main-Class,在 Spring-Boot JAR 中这个值通常为 org.springframework.boot.loader.JarLauncher
JVM 调用该类的 main 方法,传入参数即上述命令中参数
JarLauncher 构建 ClassLoader 并反射调用 META-INF/MANIFEST.MF 中的 Start-Class 类的 main 方法,通常为项目中的 Application 类
Application 类的 main 方法调用 SpringApplication.run(Application.class, args); 以最终启动应用
Slot 的核心原理是:
拓展 org.springframework.boot.loader.JarLauncher 实现根据启动命令参数读取外部 jar 包并且加入至 classpath 中
修改 META-INF/MANIFEST.MF 中的 Main-Class 为拓展的 JarLauncher
JDK 1.7 +
Spring-Boot
<project> <!-- 设置 jitpack.io 插件仓库 --> <pluginRepositories> <pluginRepository> <id>jitpack.io</id> <url>https://jitpack.io</url> </pluginRepository> </pluginRepositories> <!-- 添加 Slot Maven 插件 --> <build> <plugins> <plugin> <groupId>com.github.core-lib</groupId> <artifactId>slot-maven-plugin</artifactId> <version>LATEST_VERSION</version> <executions> <execution> <goals> <goal>transform</goal> </goals> <phase>package</phase> <configuration> <!-- optional <sourceDir/> <sourceJar/> <targetDir/> <targetJar/> --> </configuration> </execution> </executions> </plugin> </plugins> </build> </project>
参数名称 | 命令参数名称 | 参数说明 | 参数类型 | 缺省值 | 示例值 |
---|---|---|---|---|---|
sourceDir | -Dslot.sourceDir | 源jar所在目录 | File | ${project.build.directory} | 文件目录 |
sourceJar | -Dslot.sourceJar | 源jar名称 | String | ${project.build.finalName}.jar | 文件名称 |
targetDir | -Dslot.targetDir | 目标jar存放目录 | File | ${project.build.directory} | 文件目录 |
targetJar | -Dslot.targetJar | 目标jar名称 | String | ${project.build.finalName}.slot | 文件名称 |
插件的默认执行阶段是 package , 当然也可以通过使用以下命令来单独执行。
mvn slot:transform mvn slot:transform -Dslot.targetJar=your-spring-boot-app-slot.jar
默认情况下,通过 slot 升级后的 jar 名称为 ${project.build.finalName}-slot.jar ,可以通过插件配置或命令参数修改。
<plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <!-- 需要将executable和embeddedLaunchScript参数删除,目前还不能支持对该模式Jar的升级! <configuration> <executable>true</executable> <embeddedLaunchScript>...</embeddedLaunchScript> </configuration> --> </plugin>
Slot 支持使用两个参数来指定要加载的外部 jar 包:
--slot.root 即外部 jar 的根路径,缺省情况下为 Spring-Boot JAR 包的目录。
--slot.path 即外部 jar 的路径,支持设置多个,支持 ANT 表达式风格。
java -jar spring-boot-app-slot.jar --slot.root=/absolute/root/ --slot.path=foo.jar --slot.path=bar.jar java -jar spring-boot-app-slot.jar --slot.path=/relative/path/to/plugin.jar java -jar spring-boot-app-slot.jar --slot.path=/relative/path/to/**.jar
ANT 表达式通配符说明
通配符 | 含义 | 示例 |
---|---|---|
** | 任意个字符及目录 | /plugins/**.jar 即 /plugins 目录及子目录的所有 .jar 后缀的文件 |
* | 任意个字符 | /plugins/*.jar 即 /plugins 目录的所有 .jar 后缀的文件 |
? | 单个字符 | ???.jar 即当前目录所有名称为三个任意字符及以 .jar 为后缀的文件 |
通配符可以随意组合使用! 例如 /plugins/**/plugin-*-v???.jar
由于通过 Slot 加载后的外部 jar 实际上和 Spring-Boot JAR 中的 jar 处于同一个 ClassLoader 所以外部插件和母体应用之间是一个平级的关系, 外部插件可以引用母体应用中的 class 同样母体应用也可以引用外部插件的 class。
由于外部插件项目或模块通常也会依赖另外的第三方jar,所以外部插件与母体应用集成运行时也需要把另外的第三方jar通过--slot.path参数加载进来。 推荐使用 maven-dependency-plugin 在打包时将需要用到的第三方jar拷贝到指定目录,最后通过ANT表达式方式一起加载运行。
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <executions> <execution> <phase>package</phase> <goals> <goal>copy-dependencies</goal> </goals> <configuration> <includeScope>runtime</includeScope> <outputDirectory>${project.build.directory}/dependencies</outputDirectory> </configuration> </execution> </executions> </plugin>
或者使用 maven-shade-plugin 插件把相关的第三方jar资源通通打包进一个。
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.1.1</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> ... </configuration> </execution> </executions> </plugin>
另外需要注意的是,当母体应用和外部插件有相同的第三方依赖时,推荐让外部插件模块以 <scope>provided</scope> 的方式依赖之。
下面是作者想到的一些插件化拓展的方案:
IoC方式:母体应用声明接口,外部插件实现接口并且通过 @Component @Service 或其他注解让Spring 容器管理, 母体应用通过 @Resource @Autowired 来注入。
SPI方式:母体应用声明接口,外部插件实现接口并且配置于 META-INF/services/ 下,母体应用通过 ServiceLoader 加载接口的实现类。
AOP方式:外部插件通过 Spring Aspect 技术实现对母体应用的切面拦截。
1.0.1 bug 修复
1.0.0 第一个正式版发布
QQ 646742615 不会钓鱼的兔子
一、vue中的插槽 1.1 vue中插槽要解决的问题 slot 插槽 ,是用在组件中,向组件分发内容。它的内容可以包含任何模板代码,包括HTML。它会解决下面的问题: <template> <div> <p>buttonTest</p> <my-button> <!-- 处于自定义标签中的内容,如何呈现 --> button </my-butto
在使用Maven GPG Plugin之前,首先需要确认命令行下的gpg是可用的,然后如下所示配置POM。 <project> ... <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <arti
<!-- 编译插件 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.6</source> <target>1
最近开发的产品,我们是有四五个maven模块,开发阶段一直是在eclipse中运行的,然后快发版的时候,需要把这些项目打成jar包,通过命令去启动,那首先就得把这些模块项目打包,或者拷贝一些资源文件等等。 1.maven打包,首先在pom文件中加上build属性,和dependencies是同级的: <build> <!--打包出来的文件名,可以不填写,有默认值--> <finalName>T
可用的Goals Goal 描述 android:apk 创建apk文件。默认使用debug密钥对Apk签名。 如需修改可以修改配置参数为<sign><debug>false</debug></sign> android:apklib 创建apklib文件。apklib文件并不会被部署。 android:deploy 部署编译好或指定的apk文件到一个连接的设备上。在运行mvn integrati
整合spark3.3.x和hive2.1.1-cdh6.3.2碰到个问题,就是spark官方支持的hive是2.3.x,但是cdh中的hive确是2.1.x的,项目中又计划用spark-thrift-server,导致编译过程中有部分报错。其中OperationLog这个类在hive2.3中新增加了几个方法,导致编译报错。这个时候有两种解决办法: 修改spark源码,注释掉调用OperationL
插件 plugin description issues org.apache.maven.plugins maven-antrun-plugin 运行ant任务,甚至可以在pom中嵌入ant脚本 org.apache.maven.plugins maven-clean-plugin 删除构建时在项目target目录中生成的文件 org.apache.maven.plugins maven-che
maven是个项目管理工具,如果我们不告诉它我们的代码要使用什么样的jdk版本编译的话,它就会用maven-compiler-plugin默认的jdk版本来进行处理,这样就容易出现版本不匹配,以至于可能导致编译不通过的问题。 maven的默认编译使用的jdk版本貌似很低,使用maven-compiler-plugin插件可以指定项目源码的jdk版本,编译后的jdk版本,以及编码。 <plugin>
简介 compiler插件3.0之前,默认的Java编译器就的JDK自带的javac。但是从Compiler插件3.0开始(需要JDK1.6),默认的Java编译器 是javax.tools.JavaCompiler。如果仍然希望使用JDK自带的javac编译源代码,就需要为mvn命令配置forceJavacCompilerUse启动参数如:-Dmaven.compiler.forceJavacC
先定义一个父组件todo-list,和子组件 <!-- 父组件--> <template> <div> <ul> <slot>当父组件不填充内容时候,展示这行文字</slot> </ul> </div> </template> <script> export default { name: 'todo-list' }
用法和iview差不多,但是比iview多了一层。 <template slot-scope="scope"> <span v-for="(item, index) in returnTypeList" :key="index" v-show="item.key === scope.row.returnType">{{item.value}}</span> </templa
执行Spring Boot代码时,我得到如下错误: 执行目标组织失败。springframework。启动:spring boot maven插件:2.1.2。版本:在项目projectName上运行(默认cli):找不到合适的主类,请添加“mainClass”属性 我如何解决这个问题?
我正在尝试使用maven assembly插件生成zip文件程序集。我只剩下两个问题,我想知道是否有可能仅仅通过配置来解决,但作为最后的手段,我也在考虑编写自己的maven插件来扩展maven assembly插件 丢失的两块是 > 将与include模式匹配的每个依赖项放入其自己的 这是我的程序集的相关部分 这将使用
可靠的扩展 目前开源社区有不少人为Sanic框架编写了插件,这些插件很可能会在将来的某个时间帮助到你,比如缓存、模板渲染、api文档生成、Session...等等 官方也维护了一个扩展列表,见extensions
该插件为 changed.jstree 事件添加了更多信息。新数据包含在changed 事件数据属性中,并包含 selected 和 deselected 节点的列表。 changed.jstree Eventchanged plugin 选择更改时触发 (the "changed" plugin enhances the original event with more data) nodeOb
moye插件机制 出于性能考虑, moye控件只保留最小功能集合. 许多增强功能是由插件来协助完成的. 例如, 在获取校验码按钮一般情况都有一个冷却时间60秒. 点击之后60秒内是禁用的, 此时按钮文字显示冷却时间的倒计时. 此功能不方便直接写在Button控件中, 即可编写一个插件来完成. 使用方式 可以使用两种方式来激活一个控件 1、通过构造参数plugins require('moye/pl
问题内容: 我目前正在从事Java 11迁移项目,其中jaxb2-maven-plugin已用于XJC任务。由于JDK 11版本中没有XJC可执行文件,因此出现以下错误。 下面是我的pom.xml 根据Java 11的要求,我添加了必要的依赖项,例如JAXB,JAXB-IMPL等。但是仍然无法解决问题。您对此有任何建议的解决方法吗?预先感谢。 问题答案: 我通过以下参考链接解决了此问题。 http