无法运行包含依赖项的可执行jar

时间:2011-05-06 15:53:19

标签: java build maven jar classpath

如果我还不知道如何运行maven生成的可执行jar,我就会对此感到困惑并感到羞耻。

myapp-uberjar.jar包含以下内容:

com/myapp/... (all my project packages and classes are here)
META-INF/MANIFEST.MF
dependency1.jar
dependency2.jar
...

清单似乎还可以(为简洁起见,我在这里删除了一些依赖项):

Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Created-By: Apache Maven
Built-By: rabdi
Build-Jdk: 1.6.0_18
Main-Class: com.myapp.core.main.Boot
Class-Path: spring-context-3.0.5.RELEASE.jar spring-context-support-3.0.5.RELEASE.jar spring-test-3.0.5.RELEASE.jar axis-1.4.jar axis-jaxrpc-1.4.jar axis
 -saaj-1.4.jar axis-wsdl4j-1.5.1.jar commons-discovery-0.2.jar xml-api
 s-1.0.b2.jar log4j-1.2.15.jar commons-pool-1.5.4.jar hamcrest-core-1.1.jar junit-de
 p-4.8.2.jar


现在,当我去运行我的罐子时,我遇到以下错误:

D:\myapp\target>java -jar myapp-uberjar.jar
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/log4j/Logger
        at com.myapp.core.main.Boot.(Boot.java:14)
Caused by: java.lang.ClassNotFoundException: org.apache.log4j.Logger
        at java.net.URLClassLoader$1.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        ... 1 more
Could not find the main class: com.myapp.core.main.Boot. Program will exit.

为什么它不起作用?如何让它发挥作用。

谢谢!

2 个答案:

答案 0 :(得分:2)

如果您的distribute my program as single zip with my jar and libraries,那么您必须构建一个类路径。 如果你想让依赖关系将jar放到jar的外面(强烈推荐),你将不得不使用汇编插件(或其他插件来实现)。 这里有一个完整的解释如何做到这一点: pom构建元素:

<build>
    <!-- final name set the jar name, if left it 
    will give defualt "${artifactId}-${version}" -->
    <finalName>jar final name</finalName>
    <sourceDirectory>src</sourceDirectory>

        <!-- compiler plug in -->
        <plugin>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
                <source>1.6</source>
                <target>1.6</target>
            </configuration>
        </plugin>
        <!-- assembly plugin -->
        <!-- the assembly plugin is used to define your 
        final deploy output (jar, zip, dir, war, etc..)-->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-assembly-plugin</artifactId>
            <executions>
                <execution>
                    <id>assembly:package</id>
                    <phase>package</phase>
                    <goals>
                        <goal>single</goal>
                    </goals>
                    <configuration>
                        <!-- The filename of the assembled distribution 
                        file defualt ${project.build.finalName}-->
                        <finalName>${project.build.finalName}</finalName>
                        <appendAssemblyId>false</appendAssemblyId>
                        <!--    A list of descriptor files path to generate from-->
                        <descriptors>
                            <descriptor>assembly/assembly.xml</descriptor>
                        </descriptors>
                    </configuration>
                </execution>
            </executions>
        </plugin>
        <!-- jar plug in -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>2.3</version>
            <configuration>
                <archive>
                    <manifest>
                        <mainClass>fully.qualified.MainClass</mainClass>
                        <!-- to create a class path to your 
                        dependecies you have to fill true in this field-->
                        <addClasspath>true</addClasspath>
                        <!-- if you put your dependencySet/outputDirectory 
                        in the assembly file is in a specific folder (lib for example), 
                        you need to add classpathPrefix-->
                        <classpathPrefix>lib/</classpathPrefix>

                        <!-- if you defined your dependencySet/outputFileNameMapping 
                        in the assembly, instead of using the classpathPrefix, 
                        you should use customClasspathLayout, 
                        add the classpathPrefix at the begining of the 
                        customClasspathLayout, and then add the pattern of the outputFileNameMapping, 
                        NOTICE YOU NEED TO ADD '$' BEFOR OF EACH '$'.
                        supported only from version 2.3>-->
                        <!--<classpathLayoutType>custom</classpathLayoutType>
                        <customClasspathLayout>
                            lib/$${artifact.groupId}.$${artifact.artifactId}.$${artifact.extension}
                        </customClasspathLayout>-->

                    </manifest>

                    <manifestEntries>
                        <Class-Path>conf/</Class-Path>
                    </manifestEntries>
                </archive>

            </configuration>
        </plugin>

    </plugins>
</build>

汇编文件:

<?xml version="1.0" encoding="UTF-8"?>
<assembly>
    <!--the id will be add to the end of the distribution file -->
    <id>package</id>
    <formats>
        <format>zip</format>
    </formats>
    <includeBaseDirectory>true</includeBaseDirectory>


    <fileSets>
        <fileSet>
            <directory>target</directory>
            <outputDirectory></outputDirectory>
            <includes>
                <include>*.jar</include>                
            </includes>
        </fileSet>
        <fileSet>
            <directory>icons</directory>
            <outputDirectory>icons</outputDirectory>
            <includes>
                <include>**/*</include>
            </includes>
        </fileSet>
        <fileSet>
            <directory>conf</directory>
            <outputDirectory>conf</outputDirectory>
            <includes>
                <include>**/*</include>
            </includes>
        </fileSet>
    </fileSets>

    <files>
        <!-- you need to create the bat file yourself -->
        <file>
            <source>batFileName.bat</source>
            <filtered>true</filtered>
        </file>
    </files>

        <dependencySets>
            <dependencySet>
                <!--define the outputDirectory of the dependencies, 
                    NOTICE: if it's diffrent from '/'  make sure to 
                    change the classPath configuration for 
                    the maven-jar-plugin in the pom-->
                <outputDirectory>lib</outputDirectory>
                <!-- maping the dependencies jar names.
                    NOTICE : if you used this definition, you need to use 
                    customClasspathLayout classPath configuration 
                    for the maven-jar-plugin in the pomg-->
                <outputFileNameMapping>
                    ${artifact.groupId}.${artifact.artifactId}.${artifact.extension}
                </outputFileNameMapping>
                <unpack>false</unpack>
            </dependencySet>
        </dependencySets>

</assembly>

答案 1 :(得分:1)

第一种可能性:Java期望类路径上的所有jar都与可执行jar位于同一目录中。是吗?