You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Maven+Kotlin/Java中程序化获取本地仓库Jar文件

如何在测试中跨机器读取本地Maven仓库的Jar文件?

问题场景

我想在测试运行时读取本地Maven仓库里的任意Jar文件,用完整硬编码路径能成功读取:

File("/Users/myusername/.m2/repository/log4j/log4j/1.2.17/log4j-1.2.17.jar")

而且通过System.getProperty("java.class.path")能看到这个Jar已经在类路径列表里:

System.getProperty("java.class.path")

输出示例:

...:/Users/myusername/.m2/repository/io/netty/netty-transport-classes-epoll/4.1.87.Final/netty-transport-classes-epoll-4.1.87.Final.jar:/Users/myusername/.m2/repository/log4j/log4j/1.2.17/log4j-1.2.17.jar

但我不想写死完整路径,要让代码能在任何装了Maven的机器上正常运行。试过直接用文件名读取:

File("log4j-1.2.17.jar")

结果找不到文件,因为默认会去应用类路径目录里查找,而不是Maven仓库。

额外背景

我用TestContainers做集成测试的容器构建和运行,想基于带Java的基础镜像,加上公司私有仓库的可执行Jar来构建GenericContainer。已经在pom.xml里引入了对应依赖:

<dependency>
    <groupId>private.group.id</groupId>
    <artifactId>private.artifact.id</artifactId>
    <scope>test</scope>
    <classifier>exec</classifier>
    <version>${jar.version}</version>
</dependency>

当前构建容器的代码示例:

GenericContainer<Nothing>(
ImageFromDockerfile()
    .withFileFromFile(jarName, File("/Users/username/.m2/repository/groupId/artifactId/version/$jarName"))
    .withDockerfileFromBuilder { builder: DockerfileBuilder ->
        builder
            .from("urlToBaseImageWithJava")
            .copy(jarName,"/app/$jarName")
            .entryPoint("java", "-jar", "/app/$jarName")
            .build()
    }
).apply {
withNetwork(myNetwork)
start()
}

解决方法

方法1:通过类加载器定位Jar文件

利用Jar里的类反向定位Jar路径,只要Jar在类路径中就能生效,完全不需要硬编码路径:

// 替换成你依赖Jar里任意一个类的全限定名
val targetClass = Class.forName("com.your.package.YourClassFromExecJar")
val jarUrl = targetClass.protectionDomain.codeSource.location
val jarFile = File(jarUrl.toURI())

拿到这个jarFile后,就能直接传给TestContainers的withFileFromFile方法。

方法2:动态获取Maven仓库路径

Maven仓库的路径可以通过系统属性或默认规则动态获取,再拼接Jar的完整路径:

// 优先取系统属性中配置的Maven仓库路径,没有则用默认的~/.m2/repository
val mavenRepo = System.getProperty("maven.repo.local") 
    ?: "${System.getProperty("user.home")}${File.separator}.m2${File.separator}repository"

// 把groupId的点换成路径分隔符,拼接完整Jar路径
val jarFullPath = "$mavenRepo${File.separator}private${File.separator}group${File.separator}id${File.separator}private${File.separator}artifact${File.separator}id${File.separator}${jar.version}${File.separator}private.artifact.id-${jar.version}-exec.jar"
val jarFile = File(jarFullPath)

注意要根据你的依赖信息,把groupId、artifactId、version和classifier对应到路径里。

方法3:用Maven插件把Jar复制到本地目录

在pom.xml中配置maven-dependency-plugin,把依赖的可执行Jar复制到测试资源目录,之后就能用相对路径读取:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-dependency-plugin</artifactId>
            <version>3.6.0</version>
            <executions>
                <execution>
                    <id>copy-exec-jar</id>
                    <phase>process-test-resources</phase>
                    <goals>
                        <goal>copy</goal>
                    </goals>
                    <configuration>
                        <artifactItems>
                            <artifactItem>
                                <groupId>private.group.id</groupId>
                                <artifactId>private.artifact.id</artifactId>
                                <version>${jar.version}</version>
                                <classifier>exec</classifier>
                                <outputDirectory>${project.build.directory}/test-resources</outputDirectory>
                            </artifactItem>
                        </artifactItems>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

测试代码里直接读取复制后的Jar:

val jarPath = "${System.getProperty("user.dir")}${File.separator}target${File.separator}test-resources${File.separator}private.artifact.id-${jar.version}-exec.jar"
val jarFile = File(jarPath)

内容的提问来源于stack exchange,提问作者DJ-Glock

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 07:55:02