English 中文(简体)
如何为Maven构建的可执行JAR指定JVM参数
原标题:
  • 时间:2008-10-11 00:43:42
  •  标签:

当使用Maven构建可执行JAR文件时,如何指定在执行JAR文件时使用的JVM参数?

我可以使用<mainClass>指定主类。我怀疑有一个类似的JVM参数属性。特别是我需要指定最大内存(例如-Xmx500m)。

这是我的汇编插件:

  <plugin>
    <artifactId>maven-assembly-plugin</artifactId>
    <configuration>
      <descriptorRefs>
        <descriptorRef>jar-with-dependencies</descriptorRef>
      </descriptorRefs>
      <archive>
        <manifest>
          <addClasspath>true</addClasspath>
          <mainClass>com.me.myApplication</mainClass>
        </manifest>
      </archive>
    </configuration>
  </plugin>

编辑/跟进:根据帖子,似乎无法为可执行JAR指定JVM参数。

最佳回答

我不知道有任何这样的机制。JVM配置由调用java命令来指定。

这是关于JAR文件的规范,明显没有提到任何除了Main-Class以外的属性可以用于独立运行:

将此翻译为中文:http://java.sun.com/javase/6/docs/technotes/guides/jar/jar.html http://java.sun.com/javase/6/docs/technotes/guides/jar/jar.html

问题回答

首先,让我说,任何这么棘手的事情可能有很多难点。

如果你真的需要它,这种方法可能适合你。如所写,它假设"java"在调用者路径上。

概览:

  1. 在jar的清单文件中声明一个引导程序类为主类。

  2. 引导程序器在另一个进程中生成一个过程,在该过程中,我们在“真正”的主类上调用Java(传递您想要的任何命令行参数)。

  3. 将子进程的 System.out 和 System.err 重定向到引导程序的相应流。

  4. 等待子进程完成

这是一篇很好的背景文章

src/main/java/scratch/Bootstrap.java - this class is defined in pom.xml as the jar s mainclass: <mainClass>scratch.Bootstrap</mainClass>

package scratch;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;

public class Bootstrap {
    class StreamProxy extends Thread {
        final InputStream is;
        final PrintStream os;

        StreamProxy(InputStream is, PrintStream os) {
            this.is = is;
            this.os = os;
        }

        public void run() {
            try {
                InputStreamReader isr = new InputStreamReader(is);
                BufferedReader br = new BufferedReader(isr);
                String line = null;
                while ((line = br.readLine()) != null) {
                    os.println(line);
                }
            } catch (IOException ex) {
                throw new RuntimeException(ex.getMessage(), ex);
            }
        }
    }

    private void go(){
        try {
            /*
             * Spin up a separate java process calling a non-default Main class in your Jar.  
             */
            Process process = Runtime.getRuntime().exec("java -cp scratch-1.0-SNAPSHOT-jar-with-dependencies.jar -Xmx500m scratch.App");

            /*
             * Proxy the System.out and System.err from the spawned process back to the user s window.  This
             * is important or the spawned process could block.
             */
            StreamProxy errorStreamProxy = new StreamProxy(process.getErrorStream(), System.err);
            StreamProxy outStreamProxy = new StreamProxy(process.getInputStream(), System.out);

            errorStreamProxy.start();
            outStreamProxy.start();

            System.out.println("Exit:" + process.waitFor());
        } catch (Exception ex) {
            System.out.println("There was a problem execting the program.  Details:");
            ex.printStackTrace(System.err);

            if(null != process){
                try{
                    process.destroy();
                } catch (Exception e){
                    System.err.println("Error destroying process: "+e.getMessage());
                }
            }
        }
    }

    public static void main(String[] args) {
        new Bootstrap().go();
    }

}

src/main/java/scratch/App.java - 这是程序的常规入口点。

package scratch;

public class App 
{
    public static void main( String[] args )
    {
        System.out.println( "Hello World! maxMemory:"+Runtime.getRuntime().maxMemory() );
    }
}

Calling: java -jar scratch-1.0-SNAPSHOT-jar-with-dependencies.jar Returns:

Hello World! maxMemory:520290304
Exit:0

In response to David Carlson s answer, you can make it less brittle by using the java.home system property to locate the java executable instead of relying on the user s path to find it. In addition you should probably be redirecting standard input to the child process as well.

I think this can be done if you think of it this way. Generate a .bat file that will have a command:

> java .. yourClass.. -D<jvmOption1> -D<jvmOption2>...

You can try looking on this app assembler plugin for maven.

I tried it, and seems to work. I am still not clear how to make .bat file to be generated with the somewhat different content, but I think it is doable.

As another option, you may always try to create the .bat file in the resource sub folder of your project and include that sub folder with your distribution.

Ancient question but came up on my Google search for this exact problem so I m answering it.

Try

<configuation>
...
<argLine> -Xmx500m </argLine>
...
</configuation>




相关问题
热门标签