我刚刚“继承”了一个Java项目而不是来自Java背景我有时会有点迷失。 Eclipse用于在开发期间调试和运行应用程序。我已经通过Eclipse成功创建了一个.jar文件,其中包含了所有必需的外部jar,如Log4J,xmlrpc-server等。然后可以使用以下命令运行这个大的.jar:
java -jar myjar.jar
我的下一步是使用Ant(版本1.7.1)自动化构建,因此我不必让Eclipse进行构建和部署。由于缺乏java知识,这已被证明是一项挑战。项目的根目如下:
|-> jars (where external jars have been placed)
|-> java
| |-> bin (where the finished .class / .jars are placed)
| |-> src (Where code lives)
| |-> ++files like build.xml etc
|-> sql (you guessed it; sql! )
我的build.xml包含以下内容:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project basedir="." default="build" name="Seraph">
<property environment="env"/>
<property name="debuglevel" value="source,lines,vars"/>
<property name="target" value="1.6"/>
<property name="source" value="1.6"/>
<property name="build.dir" value="bin"/>
<property name="src.dir" value="src"/>
<property name="lib.dir" value="../jars"/>
<property name="classes.dir" value="${build.dir}/classes"/>
<property name="jar.dir" value="${build.dir}/jar"/>
<property name="jar.file" value="${jar.dir}/seraph.jar"/>
<property name="manifest.file" value="${jar.dir}/MANIFEST.MF"/>
<property name="main.class" value="no.easyconnect.seraph.core.SeraphCore"/>
<path id="external.jars">
<fileset dir="${lib.dir}" includes="**/*.jar"/>
</path>
<path id="project.classpath">
<pathelement location="${src.dir}"/>
<path refid="external.jars" />
</path>
<target name="init">
<mkdir dir="${build.dir}"/>
<mkdir dir="${classes.dir}"/>
<mkdir dir="${jar.dir}"/>
<copy includeemptydirs="false" todir="${build.dir}">
<fileset dir="${src.dir}">
<exclude name="**/*.launch"/>
<exclude name="**/*.java"/>
</fileset>
</copy>
</target>
<target name="clean">
<delete dir="${build.dir}"/>
</target>
<target name="cleanall" depends="clean"/>
<target name="build" depends="init">
<echo message="${ant.project.name}: ${ant.file}"/>
<javac debug="true" debuglevel="${debuglevel}" destdir="bin" source="${source}" target="${target}" classpathref="project.classpath">
<src path="${src.dir}"/>
</javac>
</target>
<target name="build-jar" depends="build">
<delete file="${jar.file}" />
<delete file="${manifest.file}" />
<manifest file="${manifest.file}" >
<attribute name="built-by" value="${user.name}" />
<attribute name="Main-Class" value="${main.class}" />
</manifest>
<jar destfile="${jar.file}"
basedir="${build.dir}"
manifest="${manifest.file}">
<fileset dir="${classes.dir}" includes="**/*.class" />
<fileset dir="${lib.dir}" includes="**/*.jar" />
</jar>
</target>
</project>
然后我跑: ant clean build-jar
并将名为seraph.jar的文件放在java / bin / jar目录中。然后我尝试使用以下命令运行此jar: java -jar bin / jar / seraph.jar
结果是控制台上的输出:
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/log4j/Logger
at no.easyconnect.seraph.core.SeraphCore.<clinit>(SeraphCore.java:23)
Caused by: java.lang.ClassNotFoundException: org.apache.log4j.Logger
at java.net.URLClassLoader$1.run(URLClassLoader.java:200)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:252)
at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:320)
... 1 more
Could not find the main class: no.easyconnect.seraph.core.SeraphCore. Program will exit.
我怀疑我在build.xml文件中做了一些非常愚蠢的事情,并且在两天的大部分时间里尝试了对配置的变化,但无济于事。非常感谢任何有关使这项工作的帮助。
哦,如果我遗漏了一些关键信息,我很抱歉。这是我第一次在SO上发帖。
答案 0 :(得分:49)
从你的ant构建文件中,我假设你想要的是创建一个JAR档案,它不仅包含你的应用程序类,还包含你的应用程序所需的其他JAR的内容。
但是,您的build-jar
文件只是将所需的JAR放入您自己的JAR中;这不会像解释here那样有效(见注释)。
尝试修改此内容:
<jar destfile="${jar.file}"
basedir="${build.dir}"
manifest="${manifest.file}">
<fileset dir="${classes.dir}" includes="**/*.class" />
<fileset dir="${lib.dir}" includes="**/*.jar" />
</jar>
到此:
<jar destfile="${jar.file}"
basedir="${build.dir}"
manifest="${manifest.file}">
<fileset dir="${classes.dir}" includes="**/*.class" />
<zipgroupfileset dir="${lib.dir}" includes="**/*.jar" />
</jar>
答案 1 :(得分:15)
在这里回答的人们提供了有用的建议后,我开始深入了解One-Jar。在一些死胡同之后(有些结果与我以前的结果完全相同,我设法让它工作。对于其他人的参考,我列出了对我有用的build.xml。
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project basedir="." default="build" name="<INSERT_PROJECT_NAME_HERE>">
<property environment="env"/>
<property name="debuglevel" value="source,lines,vars"/>
<property name="target" value="1.6"/>
<property name="source" value="1.6"/>
<property name="one-jar.dist.dir" value="../onejar"/>
<import file="${one-jar.dist.dir}/one-jar-ant-task.xml" optional="true" />
<property name="src.dir" value="src"/>
<property name="bin.dir" value="bin"/>
<property name="build.dir" value="build"/>
<property name="classes.dir" value="${build.dir}/classes"/>
<property name="jar.target.dir" value="${build.dir}/jars"/>
<property name="external.lib.dir" value="../jars"/>
<property name="final.jar" value="${bin.dir}/<INSERT_NAME_OF_FINAL_JAR_HERE>"/>
<property name="main.class" value="<INSERT_MAIN_CLASS_HERE>"/>
<path id="project.classpath">
<fileset dir="${external.lib.dir}">
<include name="*.jar"/>
</fileset>
</path>
<target name="init">
<mkdir dir="${bin.dir}"/>
<mkdir dir="${build.dir}"/>
<mkdir dir="${classes.dir}"/>
<mkdir dir="${jar.target.dir}"/>
<copy includeemptydirs="false" todir="${classes.dir}">
<fileset dir="${src.dir}">
<exclude name="**/*.launch"/>
<exclude name="**/*.java"/>
</fileset>
</copy>
</target>
<target name="clean">
<delete dir="${build.dir}"/>
<delete dir="${bin.dir}"/>
</target>
<target name="cleanall" depends="clean"/>
<target name="build" depends="init">
<echo message="${ant.project.name}: ${ant.file}"/>
<javac debug="true" debuglevel="${debuglevel}" destdir="${classes.dir}" source="${source}" target="${target}">
<src path="${src.dir}"/>
<classpath refid="project.classpath"/>
</javac>
</target>
<target name="build-jar" depends="build">
<delete file="${final.jar}" />
<one-jar destfile="${final.jar}" onejarmainclass="${main.class}">
<main>
<fileset dir="${classes.dir}"/>
</main>
<lib>
<fileset dir="${external.lib.dir}" />
</lib>
</one-jar>
</target>
</project>
我希望其他人可以从中受益。
答案 2 :(得分:2)
Cheesle是对的。类加载器无法找到嵌入式jar。如果在命令行上放置了足够的调试命令,您应该能够看到'java'命令无法将jar添加到类路径
你想要做的有时被称为'uberjar'。我发现one-jar是帮助制作它们的工具,但我还没有尝试过。当然还有很多其他方法。
答案 3 :(得分:0)
两个选项,要么引用类路径中的新jar,要么解压缩封闭jar中的所有类并重新包装整个jar!据我所知,罐子里的包装罐子没有被推荐,你将永远没有找到这个类别的例外!
答案 4 :(得分:0)
正如Cheesle所说,你可以通过以下修改解压缩你的库罐并重新装罐。
<jar destfile="${jar.file}"
basedir="${build.dir}"
manifest="${manifest.file}">
<fileset dir="${classes.dir}" includes="**/*.class" />
<zipgroupfileset dir="${lib.dir}" includes="**/*.jar" />
</jar>
Jar文件实际上只是嵌入了清单文件的zip文件。您可以将依赖项Jars提取并重新打包到应用程序的Jar文件中。
http://ant.apache.org/manual/Tasks/zip.html “Zip任务还支持将多个zip文件合并到zip文件中。这可以通过任何嵌套文件集的src属性或使用特殊的嵌套文件集zipgroupfileset来实现。”
请注意您的依赖库中涉及的许可证。从外部链接到库并在应用程序中包含库是合法的。
编辑1:我慢慢打字。格罗德里格斯打败了我。 :)
编辑2:如果您决定不能将依赖项包含到应用程序中,则必须在启动时的命令行或通过Manifest文件在Jar的类路径中指定它们。在ANT中有一个很好的命令来处理Manifest文件中类路径的特殊格式。
<manifestclasspath property="manifest.classpath" jarfile="${jar.file}">
<classpath location="${lib.dir}" />
</manifestclasspath>
<manifest file="${manifest.file}" >
<attribute name="built-by" value="${user.name}" />
<attribute name="Main-Class" value="${main.class}" />
<attribute name="Class-Path" value="${manifest.classpath}" />
</manifest>
答案 5 :(得分:0)
这是运行可执行jar时的类路径问题,如下所示:
java -jar myfile.jar
解决问题的一种方法是在java命令行上设置classpath,如下所示,添加缺少的log4j jar:
java -cp myfile.jar:log4j.jar:otherjar.jar com.abc.xyz.MyMainClass
当然最好的解决方案是将类路径添加到jar清单中,以便我们可以使用“-jar”java选项:
<jar jarfile="myfile.jar">
..
..
<manifest>
<attribute name="Main-Class" value="com.abc.xyz.MyMainClass"/>
<attribute name="Class-Path" value="log4j.jar otherjar.jar"/>
</manifest>
</jar>
以下答案演示了如何使用manifestclasspath自动化类路径清单条目的部署
答案 6 :(得分:0)
我正在使用NetBeans,并且还需要一个解决方案。谷歌搜索并从克里斯托弗的答案开始后,我设法构建了一个脚本,可以帮助您轻松地在NetBeans中执行此操作。我将这些说明放在这里以防其他人需要它们。
你要做的就是下载一个罐子。您可以使用此处的链接:http://one-jar.sourceforge.net/index.php?page=getting-started&file=ant 解压缩jar存档并查找包含one-jar-ant-task- .jar,one-jar-ant-task.xml和one-jar-boot - 的one-jar \ dist文件夹。罐。提取它们或将它们复制到我们将添加到下面脚本的路径中,作为属性one-jar.dist.dir的值。
只需在build.xml脚本末尾(来自NetBeans项目)复制以下脚本,就在/ project标记之前,将one-jar.dist.dir的值替换为正确的路径并运行one-jar目标
对于那些不熟悉运行目标的人,本教程可能有所帮助:http://www.oracle.com/technetwork/articles/javase/index-139904.html。它还向您展示了如何将源放入一个罐子中,但它们是爆炸的,而不是压缩成罐子。
<property name="one-jar.dist.dir" value="path\to\one-jar-ant"/>
<import file="${one-jar.dist.dir}/one-jar-ant-task.xml" optional="true" />
<target name="one-jar" depends="jar">
<property name="debuglevel" value="source,lines,vars"/>
<property name="target" value="1.6"/>
<property name="source" value="1.6"/>
<property name="src.dir" value="src"/>
<property name="bin.dir" value="bin"/>
<property name="build.dir" value="build"/>
<property name="dist.dir" value="dist"/>
<property name="external.lib.dir" value="${dist.dir}/lib"/>
<property name="classes.dir" value="${build.dir}/classes"/>
<property name="jar.target.dir" value="${build.dir}/jars"/>
<property name="final.jar" value="${dist.dir}/${ant.project.name}.jar"/>
<property name="main.class" value="${main.class}"/>
<path id="project.classpath">
<fileset dir="${external.lib.dir}">
<include name="*.jar"/>
</fileset>
</path>
<mkdir dir="${bin.dir}"/>
<!-- <mkdir dir="${build.dir}"/> -->
<!-- <mkdir dir="${classes.dir}"/> -->
<mkdir dir="${jar.target.dir}"/>
<copy includeemptydirs="false" todir="${classes.dir}">
<fileset dir="${src.dir}">
<exclude name="**/*.launch"/>
<exclude name="**/*.java"/>
</fileset>
</copy>
<!-- <echo message="${ant.project.name}: ${ant.file}"/> -->
<javac debug="true" debuglevel="${debuglevel}" destdir="${classes.dir}" source="${source}" target="${target}">
<src path="${src.dir}"/>
<classpath refid="project.classpath"/>
</javac>
<delete file="${final.jar}" />
<one-jar destfile="${final.jar}" onejarmainclass="${main.class}">
<main>
<fileset dir="${classes.dir}"/>
</main>
<lib>
<fileset dir="${external.lib.dir}" />
</lib>
</one-jar>
<delete dir="${jar.target.dir}"/>
<delete dir="${bin.dir}"/>
<delete dir="${external.lib.dir}"/>
</target>
祝你好运,如果对你有所帮助,不要忘记投票。
答案 7 :(得分:0)
您可以使用已经内置于ant jar任务的一些功能。
如果你转到The documentation for the ant jar task并向下滚动到&#34;合并档案&#34;那里有一个片段,用于包含你所有罐子里的所有* .class文件&#34; lib / main&#34;目录:
<jar destfile="build/main/checksites.jar">
<fileset dir="build/main/classes"/>
<restrict>
<name name="**/*.class"/>
<archives>
<zips>
<fileset dir="lib/main" includes="**/*.jar"/>
</zips>
</archives>
</restrict>
<manifest>
<attribute name="Main-Class" value="com.acme.checksites.Main"/>
</manifest>
</jar>
这个创建一个带有主类&#34; com.acme.checksites.Main&#34;的可执行jar文件,并嵌入lib / main中所有jar的所有类。 < / p>
在命名空间冲突,重复和类似事情的情况下,它不会做任何聪明的事情。此外,它将包括所有类文件,也包括您不使用的文件,因此组合的jar文件将是完整大小。
如果您需要更高级的内容,请查看one-jar和jar jar links