Execute Java programs in a consistent environment

2019-07-04 04:48发布

Where I work we have a shell script that allow us to execute arbitrary Java classes with all the necessary libraries and settings, something like:

#!/bin/sh
$JAVA_HOME/bin/java -cp LONG_LIST_OF_JARS -Xmx6g -XX:MaxPermSize=128m "$@"

And used like so:

javacorp.sh com.mycorp.SomeJob

This is obviously better than needing to specify all the java arguments explicitly every time, but I dislike that it's only manually connected to the jars configured in our Eclipse project for compiling the codebase. I'm working on a personal project and looking to similarly being able to execute arbitrary classes from the command line, and trying to identify how to best provide a consistent java environment.

Currently I'm using Eclipse to run my applications, but I'd like to be able to run them from the command line directly, or on machines that don't have Eclipse installed. In particular, I'd also like to be able to limit the scope of classes/jars that can be executed. For example, javacorp.sh lets us run anything in our src/ directory, and only javacorpunit.sh includes classes in the tests/unit/ directory in the classpath.

  • Is there a clean way to use Ant, Maven, or some other build tool to execute a configured java command at the command line, with minimal boilerplate?
  • Is there any way to hook into the .classpath file Eclipse creates? This doesn't wholly solve my problem (e.g. consistent memory settings) but it'd be nice to use data that already exists.

Edit:

Another way of phrasing my question would be "What's the cleanest way to replicate Eclipse's easy 'Run the current file's main method' button on the command line?"

3条回答
ら.Afraid
2楼-- · 2019-07-04 05:06

I think the solution to your problem is to create an executable jar. Something that can be run as follows:

java -jar myapp.jar

"look ma, no classpath" :-)

The secret is add the "Main-Class" and "Class-Path" entries into the jar's manifest file. This tells java what to run and which jars should be loaded onto the classpath:

<jar destfile="${jar.file}" basedir="${classes.dir}">
    <manifest>
        <attribute name="Main-Class" value="${jar.main.class}" />
        <attribute name="Class-Path" value="${jar.classpath}" />
    </manifest>
</jar>

To assist in creating the classpath, ANT has a really useful manifestclasspath task:

<manifestclasspath property="jar.classpath" jarfile="${jar.file}">
    <classpath>
        <fileset dir="${dist.dir}/lib" includes="*.jar"/>
    </classpath>
</manifestclasspath>

So using this example, at run-time java will expect the depedencies to reside in a "lib" subdirectory (the task will generate relative links).

Eclipse integration is tricky. A better approach for managing your classpath is to use a dependency manager like ivy, which has an Eclipse plugin. In this way both ANT and Eclipse use the same mechanism for controlling build dependencies.

Finally for a complete working example take a look at:

Hope this helps.

查看更多
来,给爷笑一个
3楼-- · 2019-07-04 05:21

Have you considered generating the shell scripts from Ant? The <pathconvert> task can create a classpath from a <fileset>.

You can create an Ant target for each kind of shell script you want. make can then call these Ant targets to generate the shell scripts.

查看更多
神经病院院长
4楼-- · 2019-07-04 05:31

With Google's Bazel build system, you can easily define as many runnable Java programs as you want, with the java_binary target. You can define as many java_binary targets as you'd like, and they can all depend on the same set (or overlapping sets) of java_library targets so you don't need to manually curate the classpath of each binary.

Additionally, with a java_binary target you can also generate a *_deploy.jar file, which is a standalone executable Jar you can run anywhere.

查看更多
登录 后发表回答