[Java/JDK] 通过命令行执行JAR包中指定Java类的main方法

1 概述:通过命令行执行JAR包中指定Java类的main方法

  • 要通过命令行执行JAR包中任意指定类的main方法,你需要了解JAR包的结构并正确使用Java命令行工具。以下是实现方法:

基本方法

java -cp your-jar-file.jar com.example.YourMainClass

其中:

  • -cp-classpath 参数指定类路径(可以是JAR文件或目录)
  • com.example.YourMainClass 是你要执行的主类的完整限定名

详细步骤

  • 确保JAR包是可执行的

虽然不是必须的,但有助于理解:
可执行的JAR包通常在MANIFEST.MF中指定了Main-Class
但我们这里要执行任意类,所以不需要依赖这个设置

  • 执行任意类的main方法:
java -cp your-application.jar com.your.package.MainClass arg1 arg2

处理依赖

  • 如果你的JAR有依赖其他JAR文件:
  • Windows系统
java -cp "your-jar-file.jar;lib/*" com.example.YourMainClass
  • Linux/Mac系统
java -cp "your-jar-file.jar:lib/*" com.example.YourMainClass

创建可执行脚本

为了方便使用,可以创建一个脚本文件:

  • Windows (run.bat)
@echo off
java -cp "your-app.jar;lib/*" %1 %*
  • Linux/Mac (run.sh)
#!/bin/bash
java -cp "your-app.jar:lib/*" "$1" "${@:2}"

然后使用方式:

./run.sh com.example.YourMainClass arg1 arg2
  • 使用jar命令查看JAR内容

如果不确定JAR中包含哪些类,可以先查看:

jar tf your-jar-file.jar

或者查找包含"Main"的类:

jar tf your-jar-file.jar | grep -i main

注意事项

  • 确保指定的类确实有public static void main(String[] args)方法
  • 类名必须包含完整的包路径
  • 如果类在某个包中,必须使用完全限定名(包括包名)

在Windows上,类路径分隔符是分号(;),在Linux/Mac上是冒号(:)

  • 示例

假设有一个JAR文件myApp.jar,其中包含类com.example.tools.DataProcessor,你想用参数input.txtoutput.txt执行它:

java -cp myapp.jar com.example.tools.DataProcessor input.txt output.txt

通过这种方式,你可以灵活地执行JAR包中的任何可执行类,而不局限于MANIFEST.MF中指定的主类。

Z 最佳实践

CASE 基于胖JAR包,指定目标类执行

胖包的好处: 只需1个JAR包(所有依赖都在这个JAR包内部了),无需再单独引入其他依赖。

打胖包的插件

  • pom.xml
<project>
    <properties>
        <maven.compiler.source>${java.version}</maven.compiler.source>
        <maven.compiler.target>${java.version}</maven.compiler.target>
		
        <maven-compiler-plugin.version>3.13.0</maven-compiler-plugin.version>
		<maven-assembly-plugin.version>3.4.2</maven-assembly-plugin.version>
        <application.startupClass>com.xxx.sdk.helper.SdkHelper</application.startupClass>
		
    </properties>
	
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-assembly-plugin</artifactId>
                <version>${maven-assembly-plugin.version}</version>
                <configuration>
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                    <!--
                    <descriptors>
                        <descriptor>src/main/assembly/assembly.xml</descriptor>
                    </descriptors>
                    -->
                    <archive>
                        <manifest>
                            <!-- 声明入口主类 [可选] -->
                            <mainClass>${application.startupClass}</mainClass>
                        </manifest>
                    </archive>
                </configuration>
                <executions>
                    <execution>
                        <id>make-assembly</id>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>${maven-compiler-plugin.version}</version>
                <configuration>
                    <source>${maven.compiler.source}</source>
                    <target>${maven.compiler.target}</target>
                    <!--<encoding>${project.build.outputEncoding}</encoding>-->
                    <!-- <skipTests>true</skipTests> --><!-- 跳过测试 -->
                    <!--<verbose>true</verbose>-->                    <!--<showWarnings>true</showWarnings>-->                    <!--<fork>true</fork>--><!-- 要使compilerVersion标签生效,还需要将fork设为true,用于明确表示编译版本配置的可用 -->
                    <!--<executable>--><!-- path-to-javac --><!--</executable>--><!-- 使用指定的javac命令,例如:<executable>${JAVA_1_4_HOME}/bin/javac</executable> -->
                    <!--<compilerVersion>${java.version}</compilerVersion>--><!-- 指定插件将使用的编译器的版本 -->
                    <!--<meminitial>128m</meminitial>--><!-- 编译器使用的初始内存 -->
                    <!--<maxmem>512m</maxmem>--><!-- 编译器使用的最大内存 -->
                    <!--<compilerArgument>-verbose -bootclasspath ${java.home}\lib\rt.jar</compilerArgument>--><!-- 这个选项用来传递编译器自身不包含但是却支持的参数选项 -->
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

Demo

  • HelloWorld
package com.xxx.sdk.helper;

import com.alibaba.fastjson2.JSON;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class HelloWorld {
    /**
     * @usage
     *   java -cp "xxx-sdk-helper-1.0.0-SNAPSHOT-jar-with-dependencies.jar" com.xxx.sdk.helper.SdkHelper "com.xxx.sdk.helper.HelloWorld"
     *   java -cp "xxx-sdk-helper-1.0.0-SNAPSHOT-jar-with-dependencies.jar" "com.xxx.sdk.helper.HelloWorld" "hello"
     * @param args
     */
    public static void main( String[] args ) {
        /**
         * 通过命令行执行指定的 Java Class
         */
        log.info("Hello world!args({}):{}", args.length, JSON.toJSONString(args));
    }
}
  • SdkHelper
package com.xxx.sdk.helper;

import com.alibaba.fastjson2.JSON;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Method;
import java.util.Arrays;

/**
 * SDK 使用助手
 */
@Slf4j
public class SdkHelper {
    public static void main( String[] args ) {
        /**
         * 通过命令行执行指定的 Java Class
         */
        log.info("args:{}", JSON.toJSONString(args));
        String className = args[0];
        try {
            Class<?> clazz = Class.forName(className);
            Method method = clazz.getMethod("main", String[].class);
            log.info("method.parameterCount:{}", method.getParameterCount());
            //创建目标对象
            Object targetObject = clazz.newInstance();
            String [] args2 = Arrays.copyOfRange(args, 1, args.length);
            method.invoke(targetObject, new Object [] { args2 } );
        } catch (Exception exception) {
            log.error("Fail to execute target class method!exception:", exception);
        }
    }
}
  • 使用示例
  • 示例1
java -cp "xxx-sdk-helper-1.0.0-SNAPSHOT-jar-with-dependencies.jar" com.xxx.sdk.helper.SdkHelper "com.xxx.sdk.helper.HelloWorld" "Hello"

out

[2025/07/22 10:46:33.851] [INFO ] [main] [com.xxx.sdk.helper.SdkHelper                                :18 main] args:["com.xxx.sdk.helper.SdkHelper","com.xxx.sdk.helper.HelloWorld","Hello"]
[2025/07/22 10:46:33.856] [INFO ] [main] [com.xxx.sdk.helper.SdkHelper                                :23 main] method.parameterCount:1
[2025/07/22 10:46:33.857] [INFO ] [main] [com.xxx.sdk.helper.SdkHelper                                :18 main] args:["com.xxx.sdk.helper.HelloWorld","Hello"]
[2025/07/22 10:46:33.858] [INFO ] [main] [com.xxx.sdk.helper.SdkHelper                                :23 main] method.parameterCount:1
[2025/07/22 10:46:33.859] [INFO ] [main] [com.xxx.sdk.helper.HelloWorld                               :18 main] Hello world!args(1):["Hello"]
  • 示例2
java -cp "xxx-sdk-helper-1.0.0-SNAPSHOT-jar-with-dependencies.jar" "com.xxx.sdk.helper.HelloWorld" "Hello"

out

[2025/07/22 10:48:54.641] [INFO ] [main] [com.xxx.sdk.helper.HelloWorld                               :18 main] Hello world!args(2):["com.xxx.sdk.helper.HelloWorld","hello"]

Y 推荐文献

X 参考文献

posted @ 2025-07-22 10:52  千千寰宇  阅读(340)  评论(0)    收藏  举报