当前位置: 首页 > news >正文

Maven uber-jar(带依赖的打包插件)maven-shade-plugin


文章目录

  • 最基础的 maven-shade-plugin 使用
  • 生成可执行的 Jar 包 和 常用的资源转换类
  • 包名重命名
  • 打包时排除依赖
  • 与其他常用打包插件比较

本文是对 maven-shade-plugin 常用配置的介绍,更详细的学习请参照 Apache Maven Shade Plugin 官方文档

通过使用 maven-shade-plugin 插件进行 Maven 的打包操作,可以将项目中的依赖一同添加到最终的项目 Jar 包内,maven-shade-plugin 插件有两个目标,我们要学习的是插件的 shade 目标,建议使用时与 Maven 生命周期的 package 阶段绑定

这中打包后带依赖的 Jar 包一般称为 uper-jarfat-jar

不管 pom.xml 是否声明了 Maven 的默认打包插件 maven-jar-plugin,也不管是否声明了其他打包插件,maven-jar-plugin 都会在 package 阶段最先执行,而 maven-shade-plugin 插件的 shade 目标,正是对 maven-jar-plugin 打包后的 Jar 包进行二次打包,同时将项目依赖的添加进去

最基础的 maven-shade-plugin 使用

按照如下配置 15~29 行,就可以正确的将 maven-shade-plugin 插件的 shade 目标与 Maven 的生命周期 package 阶段绑定,之后我们就可以通过 Maven 生命周期命令 mvn package 执行插件完成打包操作:

<!-- 模拟项目中使用的依赖 -->
<dependencies>
<!-- 依赖 commons-lang3 -->
<dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.12.0</version>
</dependency>
</dependencies><!-- 对项目构建进行配置 -->
<build><plugins><!-- 引入 maven-shade-plugin 插件 --><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-shade-plugin</artifactId><version>3.2.1</version><executions><execution><!-- 绑定 Maven 生命周期的 package 阶段 --><phase>package</phase><goals><!-- package 阶段执行时,让其调用插件的 repackage 目标 --><goal>shade</goal></goals></execution></executions></plugin></plugins>
</build>

打包后,会将打包文件放到 ${project.build.directory} 中(默认是 target 目录),如下图:

打包后的输出目录

上图中,我们重点关注两个文件:

  • ares5k-package-1.0-SNAPSHOT.jar:maven-shade-pluginmaven-jar-plugin 生成的 Jar 包进行二次打包后的 Jar 包,这个 Jar 包内已经包函项目的依赖了

  • original-ares5k-package-1.0-SNAPSHOT.jar:原始 Jar 包,maven-jar-plugin 生成的不包含项目依赖的 Jar 包,maven-shade-plugin 为了避免原始 Jar 包和新 Jar 包名字冲突,对原始 Jar 包进行了重命名,添加了 original- 前缀

maven-shade-plugin 生成的 Jar 包解压,观察其内部结构可以发现,maven-shade-plugin 打包后并没有将项目中依赖的 Jar 包直接存放,而是将依赖的 Jar 包解压后存放的:

这个特性很重要,因为 maven-shade-plugin 的另一个重要功能 <重命名> 就是基于这个实现的

解压后的目录

另外,通过上面配置创建的 Jar 包是不能够直接运行的,因为我们没有指定项目的入口类,所以只适合让其他项目引用

生成可执行的 Jar 包 和 常用的资源转换类

仿照下面 19~27 行,就可以生成可直接运行的 Jar 包:

<!-- 对项目构建进行配置 -->
<build><plugins><!-- 引入 maven-shade-plugin 插件 --><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-shade-plugin</artifactId><version>3.2.1</version><executions><execution><!-- 绑定 Maven 生命周期的 package 阶段 --><phase>package</phase><goals><!-- package 阶段执行时,让其调用插件的 repackage 目标 --><goal>shade</goal></goals></execution></executions><!-- 设置插件属性 --><configuration><transformers><!-- 添加入口类 --><transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"><!-- 入口类 --><mainClass>com.ares5k.BB</mainClass></transformer></transformers></configuration></plugin></plugins>
</build>

上面代码中 ManifestResourceTransformermaven-shade-plugin 插件提供的资源转换类,就是用来指定入口类的,除此之外,还有两个常用的资源转换类,AppendingTransformerServicesResourceTransformer

AppendingTransformer

这个资源转换类的作用,是在打包时,当碰见项目中或依赖中有同名的资源文件,要对文件内容进行追加操作,而不是覆盖

最常见的场景就是项目中引入大量 Spring 依赖时,每个 Spring 依赖都有自己的 META-INF/spring.handlersMETA-INF/spring.schemasMETA-INF/spring.factories 等文件,这种情况下利用 maven-shade-plugin 插件打包,就会发生文件覆盖的问题,如果被覆盖的文件内容和新文件的内容一样,可能会掩盖这个现象,但是当内容不一样时,就会导致项目运行错误

以 Spring 为例,演示同名文件追加操作的配置 16~27 行:

<plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-shade-plugin</artifactId><version>3.2.1</version><executions><execution><!-- 绑定 Maven 生命周期的 package 阶段 --><phase>package</phase><goals><!-- package 阶段执行时,让其调用插件的 repackage 目标 --><goal>shade</goal></goals></execution></executions><!-- 设置插件属性 --><configuration><transformers><!-- 设置 META-INF/spring.handlers 文件追加而非覆盖 --><transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer"><resource>META-INF/spring.handlers</resource></transformer><!-- 设置 META-INF/spring.schemas 文件追加而非覆盖 --><transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer"><resource>META-INF/spring.schemas</resource></transformer><!-- 设置 META-INF/spring.factories文件追加而非覆盖 --><transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer"><resource>META-INF/spring.factories</resource></transformer></transformers></configuration>
</plugin>

ServicesResourceTransformer

这个资源转换类的作用,是在打包时,当碰见同名的 SPI 接口文件时,会将文件内容追加而不是覆盖

我们使用 Java SPI 机制时,会在 META-INF/services 中创建与接口同名的文件来记录具体的实现类,当有多个同名文件时,说明该接口有多个实现类,这时候就可以利用 ServicesResourceTransformer 将文件内容合并,而不是覆盖 16~21 行:

<plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-shade-plugin</artifactId><version>3.2.1</version><executions><execution><!-- 绑定 Maven 生命周期的 package 阶段 --><phase>package</phase><goals><!-- package 阶段执行时,让其调用插件的 repackage 目标 --><goal>shade</goal></goals></execution></executions><!-- 设置插件属性 --><configuration><transformers><!-- 设置 Java SPI 追加而非覆盖 --><transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/></transformers></configuration>
</plugin>

包名重命名

重命名功能也是 maven-shade-plugin 插件的一个重要功能,这个功能可以对项目中或依赖中的包名进行重命名,包名重命名后还会把引用的地方一并修改,非常方便

这个功能的使用场景,主要是版本冲突,举个例子吧,前置条件如下:

  1. 我们的项目 A 中引用了 commons-lang3,另一个需要依赖我们项目的工程 B 也引入了 commons-lang3

  2. 两个 commons-lang3 的版本不一样,拥有相同包名、类名,但功能不同的类

基于上述条件,两个 commons-lang3 中相同包名类名的类只会被 JVM 加载一个,这就可能导致项目运行时出问题,比如调用的是未被加载的类中的功能,这时候就可以使用包名重命名功能防止 JVM 只加载一个类的情况

下面配置中 17~27 行就是对包名重新命名:

<!-- 引入 maven-shade-plugin 插件 -->
<plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-shade-plugin</artifactId><version>3.2.1</version><executions><execution><!-- 绑定 Maven 生命周期的 package 阶段 --><phase>package</phase><goals><!-- package 阶段执行时,让其调用插件的 repackage 目标 --><goal>shade</goal></goals></execution></executions><!-- 设置插件属性 --><configuration><relocations><!-- 包名重命名 --><relocation><!-- 旧包名 --><pattern>org.apache.commons.lang3</pattern><!-- 新包名 --><shadedPattern>shade.org.apache.commons.lang3</shadedPattern></relocation></relocations></configuration>
</plugin>

重命名后,项目中引用的地方也会自动修改,我们通过反编译看一下重命名后使用原包名的 .class 文件,引用的包名已经自动替换成新的名字:

包名重命名


打包时排除依赖


排除整个依赖

打包时,想排除不需要的依赖,可以使用下面配置 17~24 行,这种方式是将整个依赖排除掉,语法为 groupId:artifactId

<!-- 引入 maven-shade-plugin 插件 -->
<plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-shade-plugin</artifactId><version>3.2.1</version><executions><execution><!-- 绑定 Maven 生命周期的 package 阶段 --><phase>package</phase><goals><!-- package 阶段执行时,让其调用插件的 repackage 目标 --><goal>shade</goal></goals></execution></executions><!-- 设置插件属性 --><configuration><artifactSet><!-- 排除依赖,groupId:artifactId --><excludes><exclude>org.apache.commons:commons-lang3</exclude></excludes></artifactSet></configuration>
</plugin>

排除依赖中的部分文件

也可以更详细的配置,排除依赖中的某些文件,而不是整个依赖排除,17~30 行 :

<!-- 引入 maven-shade-plugin 插件 -->
<plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-shade-plugin</artifactId><version>3.2.1</version><executions><execution><!-- 绑定 Maven 生命周期的 package 阶段 --><phase>package</phase><goals><!-- package 阶段执行时,让其调用插件的 repackage 目标 --><goal>shade</goal></goals></execution></executions><!-- 设置插件属性 --><configuration><filters><!-- 过滤 commons-lang3 依赖中的内容--><filter><artifact>org.apache.commons:commons-lang3</artifact><excludes><!-- 排除  commons-lang3 依赖中 org/apache/commons/lang3/math 下的所有文件--><exclude>org/apache/commons/lang3/math/**</exclude><!-- 排除  commons-lang3 依赖中 META-INF 下所有扩展名是 .txt 的文件--><exclude>META-INF/*.txt</exclude></excludes></filter></filters></configuration>
</plugin>

排除项目中未使用的依赖

将项目中,引用后,实际没有使用的依赖排除掉,这个功能可以帮我们排除多余的包,来减小最后生成的 Jar 包的大小,

用的时候要注意一点,因为插件判断依赖是否使用,是通过依赖中的类是否被项目中的类引用来作为依据,假设我们使用 XML 版的 Spring,在 <bean> 中配置了依赖中的类,这个时候插件是无法检测到的,所以仍会将其排除

<!-- 引入 maven-shade-plugin 插件 -->
<plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-shade-plugin</artifactId><version>3.2.1</version><executions><execution><!-- 绑定 Maven 生命周期的 package 阶段 --><phase>package</phase><goals><!-- package 阶段执行时,让其调用插件的 repackage 目标 --><goal>shade</goal></goals></execution></executions><!-- 设置插件属性 --><configuration><!-- 将项目中未使用的依赖排除 --><minimizeJar>true</minimizeJar></configuration>
</plugin>

与其他常用打包插件比较

除了 maven-shade-plugin 之外,常用的打包插件还有 maven-jar-pluginspring-boot-maven-plugin,使用方法在我其他文章中也有记录,在此将它们作一个简单的比较

maven-shade-plugin

maven-shade-plugin 也可以将项目的依赖打进最终的项目 Jar 包中,但是其与 spring-boot-maven-plugin 不同的是,spring-boot-maven-plugin 是直接将依赖的 Jar 包放进项目的 Jar 包中,而 maven-shade-plugin 则是将依赖的 Jar 包解压,然后将解压后的文件放进最终的项目 Jar 包中

maven-shade-plugin 将依赖的 Jar 包解压后添加到项目的 Jar 包中的做法,为 maven-shade-plugin 带来了另一个重要的功能 <重命名>,因为将依赖的 Jar 包解压后都是以文件形式存在,所以 maven-shade-plugin 支持对对依赖的某个具体文件进行重命名,maven-shade-plugin 在重命名时,不只是将文件名字修改,连我们项目中对其引用的地方都会一同修改

重命名的做法可以避免版本冲突,想详细了解的可以参考我 maven-shade-plugin 的文章

spring-boot-maven-plugin

spring-boot-maven-plugin 是 Spring 提供的一个 Maven 打包插件,可以通过 maven 的插件命令运行,但是一般习惯将它与 maven 生命周期绑定,然后通过 maven 生命周期命令运行,它的特点是可以将项目中依赖的 Jar 包添加到最终生成的项目 Jar 包中

spring-boot-maven-plugin 主要是对 maven-jar-plugin 生成的项目 Jar 包进行二次打包,并将项目依赖的 Jar 包添加进项目的 Jar 包中

maven-jar-plugin

maven 生命周期中 package 阶段的默认插件,不管是否在 pom.xml 中主动声明,也不管是否有其他的 package 阶段插件被绑定,其在 package 阶段都会被最先执行

使用 maven-jar-plugin 打包时,不会将依赖的 Jar 包添加到生成的项目 Jar 包中,所以当项目中使用依赖时,需要自己准备依赖的 Jar 包,这样 maven-jar-plugin 打出的项目 Jar 包才能被成功运行

相关文章:

Maven uber-jar(带依赖的打包插件)maven-shade-plugin

文章目录 最基础的 maven-shade-plugin 使用生成可执行的 Jar 包 和 常用的资源转换类包名重命名打包时排除依赖与其他常用打包插件比较 本文是对 maven-shade-plugin 常用配置的介绍&#xff0c;更详细的学习请参照 Apache Maven Shade Plugin 官方文档 通过使用 maven-shade…...

MySQL基础(二十八)索引优化与查询优化

都有哪些维度可以进行数据库调优?简言之: 索引失效、没有充分利用到索引——索引建立关联查询太多JOIN (设计缺陷或不得已的需求)——SQL优化服务器调优及各个参数设置(缓冲、线程数等)———调整my.cnf。数据过多――分库分表 关于数据库调优的知识点非常分散。不同的DBMS&…...

初步认识性能测试和完成一次完整的性能测试

上一篇博文主要通过两个例子让测试新手了解一下测试思想&#xff0c;和在做测试之前应该了解人几点&#xff0c;那么我们在如何完成一次完整的性能测试呢&#xff1f; 测试报告是一次完整性能测试的体现&#xff0c;所以&#xff0c;这里我给出一个完整的性能测试报告&#xff…...

使用插件快速生成代码

使用插件快速生成代码 咋们常说&#xff0c;授人以鱼不如授人以渔&#xff0c;在这里给大家提供一些技巧性的东西&#xff0c;方便一些新手同学可以快速上手&#xff0c;同时&#xff0c;也提高我们的开发兴趣与开发热情&#xff01; 主要讲什么呢&#xff0c;我们来学一学如何…...

FE_Vue学习笔记 插槽 slot

插槽分为匿名插槽、具名插槽、作用域插槽。子组件中&#xff1a; 匿名插槽只能有一个&#xff1b;可以有多个具名插槽&#xff1b;作用域插槽中可以有匿名插槽和具名插槽。 当项目中一个组件可以多次复用时&#xff0c;我们可以把这个组件封装成单独的.vue文件&#xff0c;从…...

单链表的成环问题

前言&#xff1a;链表成环问题不仅考察双指针的用法&#xff0c;该问题还需要一定的数学推理和分析能力&#xff0c;看似简单的题目实则细思缜密&#xff0c;值得斟酌~ 目录 1.问题背景引入-判断链表是否成环&#xff1a; 1.1.正解&#xff1a;快慢指针 1.2 STL的集合判重 …...

横截面收益率

横截面收益率指的是在经典资产定价模型中&#xff0c;在横截面上线性确定的一个与资产风险匹配的资产收益率。 横截面收益率的预测[1] (一)变量和方法 我们主要使用月度频率数据进行检验。交易数据和公司财务数据来自于CSMAR数据库。CSMAR数据库的收益率调整了送股、配股以及拆…...

C++解析JSON JSONCPP库的使用

首先去GitHub下载JSONCPP的源码&#xff1a; JSonCpp的源码 解压后得到&#xff1a;jsoncpp-master 文件夹 需要的是&#xff1a;jsoncpp-master\src\lib_json 目录下的所有文件和 jsoncpp-master\include\json 目录下的所有文件&#xff0c;在MFC工程目录下新建两个文件夹或…...

不会Elasticsearch标准查询语句,如何分析数仓数据?

1 Elasticsearch的查询语句 ES中提供了一种强大的检索数据方式,这种检索方式称之为Query DSL,Query DSL是利用Rest API传递JSON格式的请求体(Request Body)数据与ES进行交互&#xff0c;这种方式的丰富查询语法让ES检索变得更强大&#xff0c;更简洁。 1.1 查询预发 # GET /…...

获得GitHub Copilot并结合VS Code使用

一、什么是GitHub Copilot GitHub Copilot是一种基于AI的代码生成工具。它使用OpenAI的GPT&#xff08;生成式预训练Transformer&#xff09;技术来提供建议。它可以根据您正在编写的代码上下文建议代码片段甚至整个函数。 要使用GitHub Copilot&#xff0c;您需要在编辑器中…...

Java基础-判断和循环

1 流程控制语句 在一个程序执行的过程中&#xff0c;各条语句的执行顺序对程序的结果是有直接影响的。所以&#xff0c;我们必须清楚每条语句的执行流程。而且&#xff0c;很多时候要通过控制语句的执行顺序来实现我们想要的功能。 1.1 流程控制语句分类 ​ 顺序结构 ​ 判…...

ESP32 FreeRTOS学习总结

2023.5.11 FreeRTOS中文数据手册&#xff1a;https://www.freertos.org/zh-cn-cmn-s/RTOS.html 感谢以下两位B站UP主的教程&#xff1a;孤独的二进制、Michael_ee 1.Task 创建任务常用API&#xff1a; 任务函数描述xTaskCreate()使用动态的方法创建一个任务xTaskCreatePinne…...

uniapp打包ios保姆式教程【最新】

uniapp打包 打包方式ios打包一、前往官网登录二、添加证书 三、添加标识符(Identifiers)四、添加安装ios测试机(Devices)五、获取证书profile文件六、生成并下载p12文件七、开始打包 打包方式 安卓打包直接使用公共测试证书即可打包成功&#xff0c;简单方便&#xff0c;这里我…...

Thread线程学习(2) Linux线程的创建、终止和回收

目录 1.首先要了解什么是线程ID&#xff0c;以及它的作用是什么 2.创建线程 3.终止线程 4.回收线程 5.总结 在Linux系统中&#xff0c;线程是轻量级的执行单元&#xff0c;能够在同一个进程中并发执行。本文将介绍如何在Linux环境下创建、终止和回收线程&#xff0c;并提供…...

linux-项目部署软件安装

安装jdk 操作步骤&#xff1a; 1、使用FinalShell自带的上传工具将jdk的二进制发布包上传到Linux jdk-8u171-linux-x64.tar.gz 2、解压安装包&#xff0c;命令为tar -zxvf jdk-8u171-linux-x64.tar.gz -C /usr/local 3、配置环境变量&#xff0c;使用vim命令修改/etc/profile文…...

Vue3-黑马(三)

目录&#xff1a; &#xff08;1&#xff09;vue3-基础-计算属性 &#xff08;2&#xff09; vue3-基础-xhr-基本使用 &#xff08;3&#xff09;vue3-基础-xhr-promise改造 &#xff08;1&#xff09;vue3-基础-计算属性 上面有重复的代码&#xff0c;用计算属性&#xff0…...

标准C库函数fprintf(),sprintf(),snprintf()的函数使用方法(往文件中写入数据,将变量的值转换成字符串输出)

前言 如果&#xff0c;想要深入的学习标准C库中函数fprintf()&#xff0c;sprintf()&#xff0c;snprintf()&#xff0c;还是需要去自己阅读Linux系统中的帮助文档。 具体输入命令&#xff1a; man 3 fprintf/sprintf/snprintf即可查阅到完整的资料信息。 fprintf 函数 fprin…...

不到1分钟,帮你剪完旅行vlog,火山引擎全新 AI「神器」真的这么绝?

旅行时&#xff0c;想在社交平台发布一支精美的旅行 vlog&#xff0c;拍摄剪辑需要花费多长时间&#xff1f; 20 分钟&#xff1f;一小时&#xff1f;半天&#xff1f; 在火山引擎算法工程师眼里&#xff0c;可能 1 分钟都用不了&#xff0c;因为会有 AI 替你完成。 没错&#…...

MySQL的概念、编译安装,以及自动补全

一.数据库的基本概念 1、数据&#xff08;Data&#xff09; • 描述事物的符号记录 • 包括数字&#xff0c;文字&#xff0c;图形&#xff0c;图像&#xff0c;声音&#xff0c;档案记录等 • 以“记录”形式按统一的格式进行存储 2、表 • 将不同的记录组织在一起 • …...

Jmeter常见问题和工作中遇到的问题解决方法汇总

一、标题Jmeter常见问题解决 1.1 Jmeter如何针对https协议进行接口测试&#xff1f; 解决方法&#xff1a; 协议更改为&#xff1a;https&#xff0c;端口号更改为443&#xff1b;Jmeter默认的是&#xff1a;http协议&#xff0c;端口号是&#xff1a;80 1.2 Jmeter如何解决默…...

Python:操作 Excel 折叠

💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...

第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明

AI 领域的快速发展正在催生一个新时代&#xff0c;智能代理&#xff08;agents&#xff09;不再是孤立的个体&#xff0c;而是能够像一个数字团队一样协作。然而&#xff0c;当前 AI 生态系统的碎片化阻碍了这一愿景的实现&#xff0c;导致了“AI 巴别塔问题”——不同代理之间…...

css的定位(position)详解:相对定位 绝对定位 固定定位

在 CSS 中&#xff0c;元素的定位通过 position 属性控制&#xff0c;共有 5 种定位模式&#xff1a;static&#xff08;静态定位&#xff09;、relative&#xff08;相对定位&#xff09;、absolute&#xff08;绝对定位&#xff09;、fixed&#xff08;固定定位&#xff09;和…...

C++使用 new 来创建动态数组

问题&#xff1a; 不能使用变量定义数组大小 原因&#xff1a; 这是因为数组在内存中是连续存储的&#xff0c;编译器需要在编译阶段就确定数组的大小&#xff0c;以便正确地分配内存空间。如果允许使用变量来定义数组的大小&#xff0c;那么编译器就无法在编译时确定数组的大…...

SiFli 52把Imagie图片,Font字体资源放在指定位置,编译成指定img.bin和font.bin的问题

分区配置 (ptab.json) img 属性介绍&#xff1a; img 属性指定分区存放的 image 名称&#xff0c;指定的 image 名称必须是当前工程生成的 binary 。 如果 binary 有多个文件&#xff0c;则以 proj_name:binary_name 格式指定文件名&#xff0c; proj_name 为工程 名&…...

在Mathematica中实现Newton-Raphson迭代的收敛时间算法(一般三次多项式)

考察一般的三次多项式&#xff0c;以r为参数&#xff1a; p[z_, r_] : z^3 (r - 1) z - r; roots[r_] : z /. Solve[p[z, r] 0, z]&#xff1b; 此多项式的根为&#xff1a; 尽管看起来这个多项式是特殊的&#xff0c;其实一般的三次多项式都是可以通过线性变换化为这个形式…...

LabVIEW双光子成像系统技术

双光子成像技术的核心特性 双光子成像通过双低能量光子协同激发机制&#xff0c;展现出显著的技术优势&#xff1a; 深层组织穿透能力&#xff1a;适用于活体组织深度成像 高分辨率观测性能&#xff1a;满足微观结构的精细研究需求 低光毒性特点&#xff1a;减少对样本的损伤…...

tomcat入门

1 tomcat 是什么 apache开发的web服务器可以为java web程序提供运行环境tomcat是一款高效&#xff0c;稳定&#xff0c;易于使用的web服务器tomcathttp服务器Servlet服务器 2 tomcat 目录介绍 -bin #存放tomcat的脚本 -conf #存放tomcat的配置文件 ---catalina.policy #to…...

日常一水C

多态 言简意赅&#xff1a;就是一个对象面对同一事件时做出的不同反应 而之前的继承中说过&#xff0c;当子类和父类的函数名相同时&#xff0c;会隐藏父类的同名函数转而调用子类的同名函数&#xff0c;如果要调用父类的同名函数&#xff0c;那么就需要对父类进行引用&#…...

小木的算法日记-多叉树的递归/层序遍历

&#x1f332; 从二叉树到森林&#xff1a;一文彻底搞懂多叉树遍历的艺术 &#x1f680; 引言 你好&#xff0c;未来的算法大神&#xff01; 在数据结构的世界里&#xff0c;“树”无疑是最核心、最迷人的概念之一。我们中的大多数人都是从 二叉树 开始入门的&#xff0c;它…...