SpringBoot 加载外部 Jar,实现功能按需扩展!

计算机应用数学--第一次作业 中科大 计算机应用数学 第一次作业 阅读详情

实现方案

实现这个很简单,只需要完成下面两步:

  1. 想办法将 Class 加载到 JVM
  2. 使 Spring 扫描到 Class

有时候java中的各种框架以及复杂的概念源码给我们造成了很大理解障碍,特别是Spring家族的所以先想清楚大致实现步骤比较好

将Class加载到JVM

现在我们设定需要加载的 Jar 在 /user/local/java/plugins 目录下,对于第 1 步,现在有如下几种实现方式:

  1. 扩大 -cp 由 AppClassLoader 帮我们加载外部 Jar
  2. 使用 SpringBoot 提供的启动参数 loader.path 实现
  3. 自定义 classloader 实现加载指定位置的 Jar

其中 1 和 3 是JDK提供的方案,2是 SpringBoot 扩展的方案,毕竟 SpringBoot 也需要自定义加载很多类顺带扩展了一个参数出来

方案1:扩大 -cp 由 AppClassLoader 帮我们加载外部 Jar

可以使用 classpath 指定类加载的路径,但 classpath 的生效是有条件的,这里其实对应了 Jar 包的两种启动方式:通过Jar包里的Main函数启动或者运行Jar启动

图片

SpringBoot 打包后 MANIFEST.MF 内容如下:

Manifest-Version: 1.0
Created-By: Maven JAR Plugin 3.2.2
Build-Jdk-Spec: 18
Implementation-Title: intelligent-soul
Implementation-Version: 0.0.1-SNAPSHOT
Main-Class: org.springframework.boot.loader.JarLauncher
Start-Class: com.test.MyApplication
Spring-Boot-Version: 2.6.15
Spring-Boot-Classes: BOOT-INF/classes/
Spring-Boot-Lib: BOOT-INF/lib/
Spring-Boot-Classpath-Index: BOOT-INF/classpath.idx
Spring-Boot-Layers-Index: BOOT-INF/layers.idx

所以需要使用 Main 函数启动的方式,不能使用之前的常用的 Jar 包启动方式了。对于 SpringBoot 应用 Main-Class 是 JarLauncher 所以此时启动命令要改成

java  -cp  /user/local/java/plugins org.springframework.boot.loader.JarLauncher
  • 优点:实现简单
  • 缺点:每个 Jar 包启动命令都一样了,不好区分

方案2:使用SpringBoot扩展的启动参数,使用java -jar 配合Loader.path参数

因为 Spring Boot 程序大多是打成 Jar 包,使用 java -jar boot.jar 的方式启动 (此时 -cp 无效),可以使用 loader.path 指定类加载路径加载其他 Jar,但 loader.path 生效也是有条件的:

SpringBoot 默认打包方式的Main-Class是JarLauncher

配置 Main-Class

为了使 loader.path 参数生效需要生成 Jar 包的 Main-Class 项配置为 PropertiesLauncher,在 maven 中如下配置,可参考 Using the PropertiesLauncher:

<build>
     <plugins>
         <plugin>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-maven-plugin</artifactId>
             <configuration>
                 <!-- 打包时排除scope为system的包 -->
                 <includeSystemScope>false</includeSystemScope>
                 <!-- jvm启动时通过-Dloader.path加载包,必须指定layout为ZIP,否则-Dloader.path无效!!! -->
                 <layout>ZIP</layout>
             </configuration>
             <executions>
                 <execution>
                     <goals>
                         <goal>repackage</goal>
                     </goals>
                 </execution>
             </executions>
         </plugin>
     </plugins>
     <finalName>Test</finalName>
</build>

其中 layout 可配置值如下:

1、JAR,即通常的可执行 jar

Main-Class: org.springframework.boot.loader.JarLauncher

2、WAR,即通常的可执行war,需要的 servlet 容器依赖位于 WEB-INF/lib-provided

Main-Class: org.springframework.boot.loader.WarLauncher

3、ZIP,即DIR,类似于 JAR

Main-Class: org.springframework.boot.loader.PropertiesLauncher

4、MODULE,将所有的依赖库打包(scope为provided的除外),但是不打包 Spring Boot 的任何Launcher

5、NONE,将所有的依赖库打包,但是不打包 Spring Boot 的任何 Launcher

无论启动类是 JarLauncher 或者 PropertiesLauncher,loader.path 引入的 Jar 和 Spring Boot jar 包中 BOOT-INFO/lib 包下 Jar 都是使用类加载器 org.springframework.boot.loader.LaunchedURLClassLoader 进行加载,也就是说他们使用的是同一个类加载器。这个类加载器主要就是负责加载 Jar 包里的 Jar 的加载,因为JDK没有实现该功能所以 SpringBoot 定义了该类

注意到同一个程序,打包成不同类型时,PropertiesLauncher (20s) 比 JarLauncher (8s) 启动慢很多。

方案3:自定义类加载器,加载固定目录下的jar包或者读取环境变量路径

这种方式需要程序启动的某个节点,调用自定义类加载器去加载指定目录下的 Jar 包,时间点不是很好控制。但这个定制化程度比较高。

//可以在这里调用自定义类加载
SpringApplication.run(SpringBootDemo.class, args);

方案4:通过设置-Xbootclasspath/a或者 Extention ClassLoader通过改变参数java.ext.dirs实现

会改变系统类加载器加载行为不安全不推荐!!!

加载后的类如何扫描进入Spring容器

对于业务 Jar 包类,可以预先在SpringBoot中指定好扫描包路径,那么只需要插件包路径是com.demo开头即可,如下

@SpringBootApplication(scanBasePackages = {"com.demo"})
public class SpringBootDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringBootDemoApplication.class, args);
    }

如不符合包名前缀一致的情况,需要在jar包META-INF下的spring.factories指定好自动装配的类即可如 mybatis-plus:

# Auto Configure
org.springframework.boot.env.EnvironmentPostProcessor=\
  com.baomidou.mybatisplus.autoconfigure.SafetyEncryptProcessor
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.baomidou.mybatisplus.autoconfigure.IdentifierGeneratorAutoConfiguration,\
  com.baomidou.mybatisplus.autoconfigure.MybatisPlusLanguageDriverAutoConfiguration,\
  com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration

使用 Visual Studio Code 搭建 SAP UI5 本地开发环境 工欲善其事,必先利其器。时至今日,SAP 提供了非常多的 SAP UI5 开发工具,既包含本地搭建的,也包含浏览器里远端使用的工具,比如 WebIDE 和 Business Application Studio. 我们访问下面这个链接,就能找到所有这些工具的安装或者配置步骤: https://tools.hana.ondemand.com/#sapui5 如果想选择本地开发,SAP 推荐的工具是 Visual Studio Code,也就是本文要介绍的内容。 也可以下载 WebIDE 的本地安装包,将其安 阅读详情

相关推荐

详解GPU显存和batch size的关系

GPU显存、规格指标;神经网络训练,显存占用

orangerfun的博客 6211

springboot项目使用loader.path启动服务时多版本依赖库引起的问题

只知道是不同版本导致的问题,但我在build.gradle中明明指定了使用4.1.2版本的poi,为啥使用loader.path 加载的还是5.2.2版本的呢?文件为空,导致依赖库的版本信息缺失, 这样在启动的时候,类加载器碰到多个相同的类名时,按加载器中默认的规则选择其中一个,平时在部署springboot项目时,会发现jar包太大,单是一个项目还没啥影响,但项目多了之后这个问题就比较突出了。仔细对比了下包含依赖库打出的jar包与不含依赖库打出的jar包的区别, 发现没有依赖库的jar包中的。

CXW1014的专栏 2330

使用kmplot在线进行生存分析

欢迎关注”生信修炼手册”!kmplot是一个生存分析的在线工具,最初是设计用来对肝癌中的miRNA进行生存分析,对应的文章发表在scientific reports上,链接如下https...

庐州月光的博客 1万+

SpringBoot jar包瘦身 -Dloader.path的使用

spring boot瘦身jar

weixin_42326851的博客 5471

【实战分享】低成本K型热电偶测温方案:单运放放大与STM32 ADC采集优化

本文详细介绍了低成本K型热电偶测温方案,通过单运放放大与STM32 ADC采集优化,解决了信号微弱、负电压处理和冷端补偿等核心挑战。方案采用LMV358运放和T型网络降低噪声,结合STM32的ADC校准和软件滤波,实现±0.5℃精度,物料成本控制在15元以内,适用于工业测温场景。

weixin_30839881的博客 168

sentaurus学习笔记(VDMOS仿真)(三)

在Sentaurus中,这通常意味着在2D仿真中,x轴指向下,y轴指向右。定义了在2D模拟中,网格尺寸按照一定的增长率进行扩展,这里的增长率为2.0,意味着远离最小尺寸区域的网格单元大小将是最小尺寸的两倍。定义了2D模拟中网格单元的最小尺寸为0.001微米,这有助于控制网格的最小大小,从而影响仿真的精度和计算成本。表示启用中等级别的日志信息输出,这有助于用户了解仿真过程中发生的事件和可能的问题。表示启用保存调试文件,这可以帮助用户在仿真过程中检查和验证模型的状态。这行代码设置了仿真过程中使用的线程数。

qq_52640792的博客 1807

Spring Boot Jar 包启动时如何加载外部资源

在项目有读取配置文件的地方,项目打包为 jar 后,无法从外部替换默认的配置文件,通过 Spring Boot 一系列的配置可以解决该问题。 直接谷歌搜索查到:Spring Boot Executable Jar with Classpath 其中一个 Peter Tarlos 的答案是完整的,本文的内容也是以这里为起点,通过查找官方文档来说明如何实现。 关键的 PropertiesLauncher Executable Jars Spring Boot’s executable jars, their

偶尔记一下 - mybatis.io 6673

39-高级优化技术:指令调度与乱序执行 - 手把手教你手写CPU

本文介绍了现代处理器设计中提高指令级并行性(ILP)的两种关键技术:指令调度和乱序执行。指令调度分为静态调度(由编译器完成)和动态调度(由硬件完成),后者能更好适应运行时情况但复杂度更高。乱序执行通过动态重排指令顺序提高硬件利用率,其核心组件包括重排序缓冲区、保留站和寄存器重命名。文章提供了保留站的Verilog实现示例,并分析了不同优化技术在性能、硬件开销和功耗方面的权衡。最终指出,CPU设计需根据性能、功耗等需求选择合适的优化技术。

2301_79143213的博客 85

解锁 SpringBoot 新姿势:轻松加载外部 Jar,实现功能按需扩展!

这种方式需要程序启动的某个节点,调用自定义类加载器去加载指定目录下的 Jar 包,时间点不是很好控制。但这个定制化程度比较高。//可以在这里调用自定义类加载。

m0_73735578的博客 796

扩充两个三维体积:ITK实现

在医学图像处理中,经常需要进行 3D 体积的操作,比如合并、分割等。而 ITK (Insight Segmentation and Registration Toolkit) 是一个常用的开源库,可以用于实现各种医学图像处理算法。这篇文章将介绍如何使用 ITK 实现扩充两个三维体积的操作。不过以上代码已经足够简单明了地演示了如何使用 ITK 实现扩充两个三维体积的操作。首先,我们需要准备两个三维体积的数据。这里假设这两个体积大小相同,并且已经加载到内存中了。来读取和保存体积数据,使用了。

CodeVorter的博客 204

北斗导航 | 2023 PTTI会议论文 2023 ITM会议论文 2022 ION GNSS+ 会议论文下载:ION 美国导航学会

2023 国际技术会议(ITM) 2023 精密时间和时间间隔系统和应用会议(PTTI) 2022 美国导航学会国际会议(ION GNSS +)

尘世冰封的专栏 4613

SpringBoot启动流程

运行run方法public static void main(String[] args) { SpringApplication.run(Application.class, args); } public static ConfigurableApplicationContext run(Class primarySource, String... args) { return run(new Class[] { primarySource }, args); } public static Confi

u011933469的博客 141

计算机组成原理(第三版)唐朔飞-第三章系统总线-课后习题

计算机组成原理(第三版)唐朔飞-第三章系统总线-课后习题

weixin_45735391的博客 6万+

解锁SpringBoot新姿势:轻松加载外部Jar,实现功能按需扩展!

这种方式需要程序启动的某个节点,调用自定义类加载器去加载指定目录下的 Jar 包,时间点不是很好控制。但这个定制化程度比较高。//可以在这里调用自定义类加载。

IT_1024的博客 648

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

SpringBoot 加载外部 Jar,实现功能按需扩展

这个类加载器主要就是负责加载 Jar 包里的 Jar 的加载,因为JDK没有实现该功能所以 SpringBoot 定义了该类。这种方式需要程序启动的某个节点,调用自定义类加载器去加载指定目录下的 Jar 包,时间点不是很好控制。所以需要使用 Main 函数启动的方式,不能使用之前的常用的 Jar 包启动方式了。的生效是有条件的,这里其实对应了 Jar 包的两种启动方式:通过Jar包里的Main函数启动或者运行Jar启动。,将所有的依赖库打包,但是不打包 Spring Boot 的任何。

m0_73735578的博客 638

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

SpringBoot如何加载外部Jar来实现插件功能

这种方式需要程序启动的某个节点,调用自定义类加载器去加载指定目录下的jar包,时间点不是很好控制。但这个定制化程度比较高。arduino代码解读复制代码//可以在这里调用自定义类加载 SpringApplication.run(SpringBootDemo.class, args);

2301_78976656的博客 1959

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

解锁 SpringBoot 新姿势:轻松加载外部 Jar,实现功能按需扩展

这种方式需要程序启动的某个节点,调用自定义类加载器去加载指定目录下的 Jar 包,时间点不是很好控制。但这个定制化程度比较高。//可以在这里调用自定义类加载。

jj1245_的博客 987

SpringBoot 如何加载外部 Jar 来实现插件功能

这种方式需要程序启动的某个节点,调用自定义类加载器去加载指定目录下的jar包,时间点不是很好控制。但这个定制化程度比较高。//可以在这里调用自定义类加载。

tangjieqing的博客 829
上一篇: FactoryBean 和BeanFactory的傻傻的总是分不清?
下一篇: 新来的技术总监,把DDD落地的那叫一个高级优雅!
程序员职业指南
博客等级 码龄4年 2136粉丝 960原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值