Maven Wrapper深入实战

news2024/11/15 10:43:08

概述

官网,GitHub。

Maven Wrapper,缩写为mvnw,是一个受Gradle Wrapper和Takari Wrapper启发而产生的Maven子项目,主要有以下三个用途:

  • 让开发者电脑上无需安装Maven,也不用配置环境变量,即可使用Maven构建项目;
  • 团队开发时,可让每个开发人员都保持一致的Maven版本;
  • 极个别情况下,某些特殊项目,必须使用某个指定的Maven版本;其他项目使用安装配置指定的Maven版本,不互相干扰。

另外还有一款mvnd工具和命令行,参考比Maven快2~10倍的编译工具mvnd简介与实战。

安装

安装Maven Wrapper最简单的方式是在项目(注意,可以不是Maven项目,跟Maven Wrapper版本号有关,至少需要是3.3.0;下面截图可看到并没有pom.xml文件)的根目录下运行安装命令mvn wrapper:wrapper
在这里插入图片描述
两个mvnw脚本文件的日期都是2024年5月21日,是Maven Wrapper 3.3.2版本的发布日期。
在这里插入图片描述
默认使用最新版本的Maven Wrapper,当前最新版是3.3.2
在这里插入图片描述
另外Maven Wrapper默认下载配置好的Maven,也就是mvn -v命令依赖的版本:
在这里插入图片描述
如果想指定Maven版本,则追加版本号,即使用命令mvn wrapper:wrapper -Dmaven=3.9.9指定下载3.9.9版本。

另,Maven马上迎来4这个大版本,拭目以待吧。

根据Maven Wrapper版本的不同,会在当前目录下生成3或4个文件:

  • .mvn\wrapper\maven-wrapper.jar.mvn\wrapper隐藏目录下的JAR包,没有显式告知版本号。通过JD-GUI等反编译工具当然可以查找到版本号。3.3.2版本(自什么版本开始,暂时未知)的Maven Wrapper不再生成此文件(下文有原因分析)。
  • .mvn\wrapper\maven-wrapper.properties:配置文件,内容如下,据此可知使用的Maven和Maven Wrapper版本,可解答上面的问题。注:Maven Wrapper有些版本此文件只有一个distributionUrl,无法一眼看出Wrapper版本,这是Takari Maven Wrapper。
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.6/apache-maven-3.8.6-bin.zip
wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar

另外,如果不再生成JAR包,则maven-wrapper.properties配置文件也会不一样:

wrapperVersion=3.3.2
distributionType=only-script
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip
  • mvnw:用于Linux、Mac等系统的脚本;
  • mvnw.cmd:用于Windows系统的脚本;

下载安装

因为执行mvn wrapper:wrapper命令安装Maven Wrapper需提前下载并配置好Maven。如果开发者电脑里没有Maven,咋办呢。

参考stackoverflow,从这里选择一个版本,推荐最新版。一般直接下载第一个文件即可,形如maven-wrapper-distribution-x.x.x-bin.zip的压缩文件。解压缩,然后手动添加.mvn/wrapper/maven-wrapper.properties配置文件并指定想要使用的Maven版本(参考上文);提交到Git Server前,最好删除压缩包里的JAR文件。

确实有点麻烦。

Takari

上面提到JD-GUI可反编译maven-wrapper.jar文件。值得注意的是,除了Apache Maven Wrapper外,还有个Takari Maven Wrapper:
在这里插入图片描述
上面截图,Takari Maven Wrapper使用的包路径是apache。

在Maven仓库里搜索,最后一个GAV如下:

<dependency>
	<groupId>io.takari</groupId>
	<artifactId>maven-wrapper</artifactId>
	<version>0.5.6</version>
</dependency>

时间停留在2019年12月4日。
在这里插入图片描述
这两者的关系是:Maven Wrapper,最初由Takari团队开发。后来这个工具被广泛采纳和使用,成为Maven官方推荐的工具。因此之前的GAV不再发布新版本,最新的GAV如下:

<dependency>
	<groupId>org.apache.maven.wrapper</groupId>
	<artifactId>maven-wrapper</artifactId>
	<version>3.3.2</version>
</dependency>

版本号和上面提到的3.3.2对应得上。

版本控制系统

可能有些朋友会有疑问,使用Maven Wrapper无需下载安装Maven,更无需配置环境变量,但上面却使用mvn wrapper:wrapper命令来安装Maven Wrapper,mvn命令的使用不是得提前安装并配置Maven么。

是不是有种鸡生蛋,还是蛋生鸡的既视感?

实际上,执行mvn wrapper:wrapper命令生成的几个文件,是需要一并提交到Git版本管理系统里。也就是说,从GitHub或GitLab上clone下来的某个项目。如果有这几个文件,则不管你是否安装并配置过Maven,都会使用此项目指定的Maven版本,也就是Maven Wrapper通过配置文件maven-wrapper.properties指定的版本:
在这里插入图片描述
从截图可知,默认在C盘用户目录下安装zip文件并解压,然后设置MAVEN_HOME指向解压缩后的目录。另外,最新版Maven Wrapper,即3.3.2版本会删除压缩包,毕竟留着也没用。

反过来,正是因为这几个文件需要提交到Git Server,如Maven Wrapper早期版本会生成JAR包,此文件说大不大,说小也并不小,40~50k左右。
在这里插入图片描述
Git版本管理系统有一个最佳实践是:提交代码、配置等文本文件,尽可能不要提交图片、JAR包等二进制文件。

有些朋友可能会说,就那么50k,也没有什么大碍吧。编码洁癖强迫症,像我就是,真受不了。

或者,有其他朋友会说,这些二进制文件并不会更新,一次性提交,后期不会更新,不要紧的。

等等,真的不会更新吗?

指定Maven Wrapper版本

不管是使用Takari Maven Wrapper,还是使用Apache Maven Wrapper,就和使用其他三方依赖,如Spring Boot版本号,肯定是尽可能使用次新版,毕竟新版本修复若干问题和优化若干性能等。

然后上面提到的命令行追加的版本号针对的是Maven的版本。如果想要使用某个版本的Maven Wrapper,而不是最新版的Maven Wrapper,该怎么做呢。

还是用命令行,此处对一个空的文件夹执行命令mvn wrapper:wrapper:3.1.0
在这里插入图片描述
执行失败,报错如下:
在这里插入图片描述
No plugin descriptor found at META-INF/maven/plugin.xml。什么鬼,我想下载的是3.1.0版本,怎么会是\wrapper\wrapper\3.0.3\wrapper-3.0.3.jar这个JAR,去D盘一看,确实有这个JAR,Maven仓库也有这个JAR:
在这里插入图片描述
这里给出一个未加证实的猜测:Maven命令执行时从Maven仓库下载指定版本的JAR,如果没有指定版本的JAR,会做降级处理,下载低版本的JAR。比如我想要的是3.1.0版本,结果会下载3.0.3,毕竟Maven仓库里只有这个版本。至于那个报错,No plugin descriptor是Maven Wrapper的插件扫描机制的报错。

稍加分析,不难得知,mvn wrapper:wrapper是经过缩写的命令行,如果需要指定版本,必须写全GAV信息,即groupId、artifactId、version。但是很不幸,还是相同的报错:No plugin descriptor found at META-INF/maven/plugin.xml

经过各种反复试错,以及对报错的分析plugin.xml,加上之前经常看到maven-xxx-plugin
在这里插入图片描述
于是想到执行命令:mvn org.apache.maven.plugins:maven-wrapper-plugin:wrapper,终于执行成功:
在这里插入图片描述
可以看到命令执行成功,虽然还是使用最新版Maven Wrapper;但是,至少我们知道mvn wrapper:wrappermvn org.apache.maven.plugins:maven-wrapper-plugin:wrapper命令的缩写。

现在需要做的就是加上版本号。

姿势:mvn org.apache.maven.plugins:maven-wrapper-plugin:3.1.0:wrapper

经过试错,发现早期版本的Apache Maven Wrapper(区别于Takari Maven Wrapper)不支持在非Maven工程目录下执行mvn wrapper:wrapper
在这里插入图片描述
直到3.3.0版本,才开始支持对非Maven项目(没有pom.xml文件)执行mvn wrapper:wrapper
在这里插入图片描述
经过验证,Apache Maven Wrapper第一个版本,即3.1.0,可从Maven仓库搜索得知,还是存在maven-wrapper.jar这个JAR文件:
在这里插入图片描述

后面Apache Maven团队优化这个问题,即执行mvn wrapper:wrapper命令时不生成JAR文件,当然就不用提交到Git Server。JAR文件也参与到版本控制系统里,确实很不合适。

org.apache.maven.plugins:maven-wrapper-plugin和org.apache.maven.wrapper:maven-wrapper

上面在诸般尝试切换Maven Wrapper版本时,发现两个很类似的GAV:

<dependency>
	<groupId>org.apache.maven.plugins</groupId>
	<artifactId>maven-wrapper-plugin</artifactId>
	<version>3.3.2</version>
</dependency>

以及

<dependency>
	<groupId>org.apache.maven.wrapper</groupId>
	<artifactId>maven-wrapper</artifactId>
	<version>3.3.2</version>
</dependency>

两者都可在Maven参考搜索,但版本号有些许不同。那有什么区别呢?

org.apache.maven.plugins:maven-wrapper-plugin:如命名所示,这是一个Maven插件,用于帮助项目创建Maven Wrapper;通过Maven插件的方式执行,可生成mvnw脚本和.mvn目录。

org.apache.maven.wrapper:maven-wrapper:是Maven Wrapper的实际实现,包含Maven Wrapper的核心逻辑和脚本文件,用于包装和管理Maven的版本。maven-wrapper是在mvnw脚本中调用的库,负责下载和执行指定版本的Maven。它确保即使在没有预先安装Maven的情况下,项目也能使用指定的Maven版本来进行构建。

前者是插件,后者是具体的实现类库。

其他诸多Maven插件和实现库,原理类似。

升级Maven Wrapper

上面也提到更高版本更加合理,对一个传统的非Maven项目执行mvn wrapper:wrapper变成Maven项目,是很合理的需求及业务场景。

所以,升级Maven Wrapper也是理所当然的。

对一个已经使用Maven Wrapper的Maven项目,执行命令mvn wrapper:wrapper会升级Maven Wrapper版本到最新,升级还是涉及那几个文件:两个脚本文件、一个配置文件、一个可选的JAR文件。如果指定版本号,则升级到指定的版本号。

也就是说,使用早期版本的Maven Wrapper(所有Takari版本的Maven Wrapper,以及早期的Apache Maven Wrapper),执行命令会更新JAR,这个JAR是需要提交到Git Server的。Maven团队也意识到这个问题,在某个版本后,执行命令不再生成JAR文件,只剩下3个文件。

不同版本的潜在问题

上面提到Maven Wrapper可以使得同一个开发团队里的不同开发者使用相同版本的Maven。不过,鄙人用了8年多Maven,也没怎么去关注过CI/CD系统使用的Maven版本,倒一直没有遇到Maven版本不同带来的任何问题。

只能说,使用不同的大版本(如Maven 3.3和Maven 3.6)的Maven,可能存在如下潜在的问题:

  • 构建结果不一致:不同的 Maven 版本可能对插件、依赖解析、配置处理等有不同的行为。如果开发者使用的 Maven 版本不一致,可能会导致在不同机器上构建相同项目时产生不同的结果。这种不一致会在 CI/CD 流水线中表现得更加明显,特别是在构建成功与失败的标准上;
  • 插件兼容性问题:Maven 插件可能针对特定的 Maven 版本进行开发和优化。使用较新的 Maven 版本可能会默认启用或弃用一些功能,而较旧的 Maven 版本则可能不支持这些功能,导致插件无法正常运行或行为不一致;
  • 性能差异:Maven 的不同版本在性能上可能有显著差异。新版本通常会修复一些性能问题或引入更高效的依赖管理机制,但旧版本可能仍然存在这些性能问题,这会导致构建时间上的差异,进而影响开发效率;
  • Bug 和功能特性:新版本的 Maven 通常修复了一些已知的 bug,并引入了新的功能。如果团队成员使用的版本不一致,可能会导致部分成员无法使用新功能,或者某些问题在新版本中已被修复但在旧版本中仍然存在,这会导致团队协作中的额外沟通和问题排查成本;
  • 配置文件解析:Maven 的某些配置文件解析逻辑可能在不同版本中有所不同,尤其是在处理复杂的继承结构、Profile、插件配置等方面。这会导致同一套配置文件在不同的 Maven 版本中产生不同的解析结果,从而影响构建过程;
  • 依赖解析问题:Maven 版本之间的依赖解析算法可能会有所不同。新版本可能会更智能地处理冲突和版本解析,而旧版本可能存在解析错误或不完善的地方。这种差异会导致开发者在解析依赖时遇到不同的问题,甚至导致构建失败。

推荐和CI系统使用的Maven保持一致,或引入Maven Wrapper。

使用脚本

以Windows操作系统为例,双击mvnw.cmd文件,会根据.mvn\wrapper\maven-wrapper.properties文件里的distributionUrl,去指定的地方(https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/,这个地址基本上固定不变)下载指定版本的Maven压缩包(如上是3.8.6版本),存储到C盘用户目录下,如C:\Users\johnny\.m2\wrapper\dists\apache-maven-3.8.6-bin\1ks0nkde5v1pk9vtc31i9d0lcd。随机生成的文件夹。

国内网络因为一些原因,下载速度可能会非常慢(不使用VPN,浏览器打开上述下载地址,速度还行;命令行会慢很多)。下载成功后,解压缩zip包,解析项目pom.xml文件,开启新一轮的漫长等待:
在这里插入图片描述
默认情况下,三方依赖JAR会下载到C:\Users\johnny\.m2\repository下。

切换源

上面提到Maven Wrapper速度慢(应该是仅大陆用户吧)的问题:

  • 下载Maven压缩zip包
  • 下载pom.xml文件引入的依赖

针对第一个问题,可考虑修改配置文件maven-wrapper.properties里的distributionUrl指向阿里云或别的镜像仓库:https://mirrors.aliyun.com/apache/maven/maven-3/

阿里云只维护这么几个Maven版本,少得有点过分:
在这里插入图片描述

针对第二个问题,

一般本机安装Maven时,都会在conf/settings.xml中配置maven的国内源,但使用Maven Wrapper时并没有看到类似setting.xml的配置文件。此时可在项目pom.xml中直接指定国内源。在公司开发多个项目时,则可考虑在parent父工程里的pom.xml文件里添加类似配置:

<repositories>
	<repository>
		<id>aliyun</id>
		<url>https://maven.aliyun.com/repository/maven-public/</url>
	</repository>
</repositories>
<pluginRepositories>
	<pluginRepository>
		<id>aliyun</id>
		<url>https://maven.aliyun.com/repository/maven-public/</url>
	</pluginRepository>
</pluginRepositories>

mvnw.cmd

还是以Windows系统为例,最新版(3.3.2版本)的mvnw.cmd文件,去掉License相关注释(@REM开头的行就是注释)后如下:

<# : batch portion
@REM Optional ENV vars
@REM   MVNW_REPOURL - repo url base for downloading maven distribution
@REM   MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven
@REM   MVNW_VERBOSE - true: enable verbose log; others: silence the output
@REM ----------------------------------------------------------------------------

@IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0)
@SET __MVNW_CMD__=
@SET __MVNW_ERROR__=
@SET __MVNW_PSMODULEP_SAVE=%PSModulePath%
@SET PSModulePath=
@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @(
  IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B)
)
@SET PSModulePath=%__MVNW_PSMODULEP_SAVE%
@SET __MVNW_PSMODULEP_SAVE=
@SET __MVNW_ARG0_NAME__=
@SET MVNW_USERNAME=
@SET MVNW_PASSWORD=
@IF NOT "%__MVNW_CMD__%"=="" (%__MVNW_CMD__% %*)
@echo Cannot start maven from wrapper >&2 && exit /b 1
@GOTO :EOF
: end batch / begin powershell #>

$ErrorActionPreference = "Stop"
if ($env:MVNW_VERBOSE -eq "true") {
  $VerbosePreference = "Continue"
}

# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties
$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl
if (!$distributionUrl) {
  Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties"
}

switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) {
  "maven-mvnd-*" {
    $USE_MVND = $true
    $distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip"
    $MVN_CMD = "mvnd.cmd"
    break
  }
  default {
    $USE_MVND = $false
    $MVN_CMD = $script -replace '^mvnw','mvn'
    break
  }
}

# apply MVNW_REPOURL and calculate MAVEN_HOME
# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-<version>,maven-mvnd-<version>-<platform>}/<hash>
if ($env:MVNW_REPOURL) {
  $MVNW_REPO_PATTERN = if ($USE_MVND) { "/org/apache/maven/" } else { "/maven/mvnd/" }
  $distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace '^.*'+$MVNW_REPO_PATTERN,'')"
}
$distributionUrlName = $distributionUrl -replace '^.*/',''
$distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$',''
$MAVEN_HOME_PARENT = "$HOME/.m2/wrapper/dists/$distributionUrlNameMain"
if ($env:MAVEN_USER_HOME) {
  $MAVEN_HOME_PARENT = "$env:MAVEN_USER_HOME/wrapper/dists/$distributionUrlNameMain"
}
$MAVEN_HOME_NAME = ([System.Security.Cryptography.MD5]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join ''
$MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME"

if (Test-Path -Path "$MAVEN_HOME" -PathType Container) {
  Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME"
  Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD"
  exit $?
}

if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) {
  Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl"
}

# prepare tmp dir
$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile
$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir"
$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null
trap {
  if ($TMP_DOWNLOAD_DIR.Exists) {
    try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null }
    catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" }
  }
}

New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null

# Download and Install Apache Maven
Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..."
Write-Verbose "Downloading from: $distributionUrl"
Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName"

$webclient = New-Object System.Net.WebClient
if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) {
  $webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD)
}
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null

# If specified, validate the SHA-256 sum of the Maven distribution zip file
$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum
if ($distributionSha256Sum) {
  if ($USE_MVND) {
    Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties."
  }
  Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash
  if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) {
    Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property."
  }
}

# unzip and move
Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null
Rename-Item -Path "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" -NewName $MAVEN_HOME_NAME | Out-Null
try {
  Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null
} catch {
  if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) {
    Write-Error "fail to move MAVEN_HOME"
  }
} finally {
  try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null }
  catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" }
}

Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD"

脚本解读:

参考

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2080395.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java面试宝典-java基础02

Java面试宝典-java基础02 11、使用 final 关键字修饰一个变量时,是引用不能变,还是引用的对象不能变?12、this 和super 关键字的作用13、在 Java 中,为什么不允许从静态方法中访问非静态变量?14、final 与 static 的区别?15、int可以强制转换为byte吗?16、char 型变量中…

安卓中synchronized 关键字 的作用和介绍

在Java中&#xff0c;synchronized 关键字用于控制多线程环境下对方法或代码块的访问&#xff0c;确保在同一时刻只有一个线程可以执行该方法或代码块。当你在方法声明中使用 synchronized 关键字&#xff0c;这意味着任何线程在调用该方法之前必须获得该方法所属对象的锁。这通…

Android Abort message: ‘Error, cannot access an invalid/free‘d bitmap here!‘

Android Abort message: Error, cannot access an invalid/freed bitmap here! Error, cannot access an invalid/freed bitmap here 在某些Glide加载场景中&#xff0c;如果Glide把Bitmap加载放入到view后&#xff0c;又去从view里面取Bitmap&#xff0c;会抛上述NE错误。 解…

代码随想录 刷题记录-18 动态规划(2)01背包问题、习题

一、01背包理论基础 例题&#xff1a;46. 携带研究材料 01 背包 有n件物品和一个最多能背重量为w 的背包。第i件物品的重量是weight[i]&#xff0c;得到的价值是value[i] 。每件物品只能用一次&#xff0c;求解将哪些物品装入背包里物品价值总和最大。 暴力解法&#xff1a…

大模型实战-FinGLM解析金融财报做RAG经验参考篇

大模型实战-FinGLM金融财报解析实战 https://modelscope.cn/datasets/modelscope/chatglm_llm_fintech_raw_dataset/summary 详细解读&#xff1a; https://modelscope.cn/models/finglm/FinGLM/summary 背景&#xff1a;解读pdf版本的公司财务年报&#xff0c;构建问答模型…

zsh: command not found: brew(M系列芯片)

利用官网的命令安装完brew /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"查看版本&#xff0c;提示找不到命令 % brew -v zsh: command not found: brew解决方法&#xff0c;在终端中执行以下命令&#xff0c…

EV代码签名证书——消除软件下载时的安全警告

开发公司和软件开发人员在发布应用程序后&#xff0c;当用户尝试下载并安装应用程序时&#xff0c;被SmartScreen识别为不常见或尚未建立起良好的信誉度&#xff0c;系统就会发出警告&#xff0c;提示用户该应用程序可能对电脑构成风险。这会导致软件下载率大幅度下降。 EV代码…

鸿蒙XComponent组件的认识

概述&#xff1a; XComponent组件作为一种渲染组件&#xff0c;通常用于满足开发者较为复杂的自定义渲染需求&#xff0c;例如相机预览流的显示、游戏画面的渲染、自定义视频播放器等等。其中Native API是其核心内容&#xff01; 其可通过指定其type字段来实现不同的功能&…

Comsol 声学黑洞梁式结构的振动能量收集器

声学黑洞梁式结构是一种用于收集振动能量的装置&#xff0c;其工作原理类似于光学中的黑洞概念。它可以将周围环境中的声波能量转化为可用的电能。声学黑洞梁式结构通常由以下几个主要组成部分构成&#xff1a; 1. 梁&#xff1a;梁是主要的振动结构&#xff0c;可以是金属、陶…

mac nvm安装及使用(nvm安装指定版本node npm pnpm)

mac nvm安装及使用&#xff08;nvm安装指定版本node npm pnpm&#xff09; 1.卸载电脑的node 打开终端&#xff1a;依次执行以下命令&#xff1a; sudo rm -rf /usr/local/bin/npm sudo rm -rf /usr/local/share/man/man1/node.1 sudo rm -rf /usr/local/lib/dtrace/node.d s…

JVM极简教程

基础概念 1.1. Java 虚拟机 是运行 Java字节码的虚拟机 1.2. JVM跨平台原理 JVM在不同的系统&#xff08;Linux、Windows、MacOS&#xff09;上有不同的实现&#xff0c;目的是在使用相同的字节码&#xff0c;它们都会给出相同的结果 JVM跨平台本质&#xff1a;不同操作系统…

高标准农田灌区信息化如何提高灌溉效率

高标准农田灌区的信息化建设&#xff0c;是现代农业发展的重要一环&#xff0c;旨在通过先进的信息技术手段优化水资源管理&#xff0c;提高灌溉效率&#xff0c;保障粮食安全&#xff0c;同时促进农业可持续发展。这一过程不仅涉及硬件设施的升级&#xff0c;还包括软件系统、…

第2章 双向链表

双向链表 概念 对链表而言&#xff0c;双向均可遍历是最方便的&#xff0c;另外首尾相连循环遍历也可大大增加链表操作的便捷性。因 此&#xff0c;双向循环链表&#xff0c;是在实际运用中是最常见的链表形态。 基本操作 与普通的链表完全一致&#xff0c;双向循环链表虽然…

PHP房屋出售出租多端多平台预约系统小程序源码

&#x1f3e0;&#x1f511;「房屋出售出租多端运营系统」——房产管理新纪元&#xff0c;一键掌控所有&#xff01;&#x1f680; &#x1f3e1; 开篇直击&#xff1a;房产市场新利器&#xff0c;轻松管理不再是梦&#xff01; 亲们&#xff0c;还在为房屋出售或出租的繁琐流…

【IC设计】跨时钟异步处理系列——单比特跨时钟

文章目录 建立时间和保持时间单比特信号的跨时钟处理慢时钟域的信号传输到快时钟域打两拍 快时钟域的信号传输到慢时钟域方案一 脉冲展宽同步 (打拍打拍&#xff0c;进行或)代码原理图 方案二 脉冲电平检测双触发器同步边沿检测代码原理图 建立时间和保持时间 所谓的建立时间或…

python可视化-漏斗图(转化分析)

1、数据生成 from scipy import stats# 构造数据 stage [浏览,加入购物车,下单,支付,交易成功] values [] for i in range(len(stage)):values.append(int(1000*stats.expon.pdf(i, scale0.95))) 2、基于漏斗图的转化分析 from pyecharts import options as opts from pye…

HarmonyOs如何获取rawfile目录下的所有文件列表

最近在做一个功能&#xff0c;需要使用获取rawfile下目录的所有文件 参考连接为&#xff1a; zRawfile-模块-C API-Localization Kit&#xff08;本地化开发服务&#xff09;-应用框架 - 华为HarmonyOS开发者 (huawei.com) 需要使用到native实现&#xff0c;实现步骤&#…

redis面试(二十四)Semaphore锁实现

Semaphore也是redis分布式锁支持的一种&#xff0c;同步组件 之前给大家的讲解的锁&#xff0c;基本上都是同时间只能一个客户端获取这个锁&#xff0c;然后做一些事情&#xff0c;处理完了以后释放锁 Semaphore&#xff0c;信号量&#xff0c;他作为一个锁机制&#xff0c;可以…

Charles苹果手机https抓包

1、电脑设置Charles代理端口 1)设置代理端口 Proxy-》Proxying Settings-》HTTP Proxy 设置端口 2)设置监控的代理地址 Proxy-》SSL Proxying Settings 添加Add允许所有地址*.* 2、电脑导入Charles的ssl证书 3、电脑查看Charles的IP地址和端口 4、手机无线wifi配置代理 5、手…

kubernetes HPA

K8S的HPA介绍 在Kubernetes&#xff08;K8S&#xff09;集群管理中&#xff0c;Horizontal Pod Autoscaler&#xff08;HPA&#xff09;是一种关键的自动扩缩容机制&#xff0c;用于根据当前负载情况自动调整Pod副本的数量。这一机制能够显著提升应用的响应能力和资源利用率&a…