Java 运行 JAR 时出现 ClassNotFoundException,在 IntelliJ IDEA 中运行时没有错误
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19757355/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
ClassNotFoundException upon running JAR, no errors while running in IntelliJ IDEA
提问by Andrei R?nea
I'm just starting to build Java apps (I do have .NET experience) and I was trying to build a small test app whose whole code is this :
我刚刚开始构建 Java 应用程序(我确实有 .NET 经验),我试图构建一个小型测试应用程序,其整个代码如下:
package com.company;
import com.microsoft.sqlserver.jdbc.SQLServerDataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class Main {
public static void main(String[] args) throws SQLException {
System.out.println("Buna lume!");
SQLServerDataSource ds = new SQLServerDataSource();
ds.setIntegratedSecurity(true);
ds.setServerName("localhost");
ds.setPortNumber(1433);
ds.setDatabaseName("Test");
Connection con = ds.getConnection();
String SQL = "SELECT * FROM Test WHERE ID = ?";
PreparedStatement stmt = con.prepareStatement(SQL);
stmt.setInt(1, 2);
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
System.out.println(rs.getInt(1) + ", " + rs.getString(2));
}
rs.close();
stmt.close();
con.close();
}
}
If I run the app in the IDE (IntelliJ IDEA 12.1.6 Community Edition), having the SQL Server available, the app runs fine doing exactly what it should.
如果我在 IDE(IntelliJ IDEA 12.1.6 社区版)中运行该应用程序,并且 SQL Server 可用,则该应用程序运行良好,完全符合它的要求。
The SQL Server Driver is downloaded from Microsoft and added as an External Library. I have created an artifact as JAR file :
SQL Server 驱动程序从 Microsoft 下载并作为外部库添加。我创建了一个工件作为 JAR 文件:
Now, if I include the sqljdbc4.jar in the cliTest.jar (my JAR) the resulted JAR is fat (550kB and includes the classes in that JAR too). Or I can exclude it. Either way, running
现在,如果我将 sqljdbc4.jar 包含在 cliTest.jar(我的 JAR)中,则生成的 JAR 会很胖(550kB 并且也包含该 JAR 中的类)。或者我可以排除它。无论哪种方式,运行
java -jar cliTest.jar
Results in
结果是
Buna lume!
Exception in thread "main" java.lang.NoClassDefFoundError: com/microsoft/sqlserv
er/jdbc/SQLServerDataSource
at com.company.Main.main(Main.java:15)
Caused by: java.lang.ClassNotFoundException: com.microsoft.sqlserver.jdbc.SQLSer
verDataSource
at java.net.URLClassLoader.run(Unknown Source)
at java.net.URLClassLoader.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
I bet I'm missing something quite basic but I just can't figure out what exactly is causing this.
我敢打赌我错过了一些非常基本的东西,但我无法弄清楚究竟是什么导致了这种情况。
LE1 : I tried adding sqljdbc4.jar (although it didn't seem necessary) and sqljdbc_auth.dll in the directory containing the JAR but still no change.
LE1:我尝试在包含 JAR 的目录中添加 sqljdbc4.jar(虽然它似乎没有必要)和 sqljdbc_auth.dll 但仍然没有变化。
Later edit 2 : Based on Nikolay's answer I've done the following :
稍后编辑 2 :根据尼古拉的回答,我做了以下工作:
- Deleted the existing artifact
- Created a new artifact like so :
- 删除了现有的工件
- 创建了一个新的工件,如下所示:
.. and resulted this :
.. 结果是:
Build -> Build artifacts -> cliTest.jar -> Rebuild
CMD Prompt at the folder containing :
构建 -> 构建工件 -> cliTest.jar -> 重建
包含以下文件夹的 CMD 提示:
[cliTest.jar 566 KB was generated]
[cliTest.jar 566 KB 已生成]
java -jar cliTest.jar
java -jar cliTest.jar
Now I get :
现在我得到:
Exception in thread "main" java.lang.SecurityException: Invalid signature file d
igest for Manifest main attributes
at sun.security.util.SignatureFileVerifier.processImpl(Unknown Source)
at sun.security.util.SignatureFileVerifier.process(Unknown Source)
at java.util.jar.JarVerifier.processEntry(Unknown Source)
at java.util.jar.JarVerifier.update(Unknown Source)
at java.util.jar.JarFile.initializeVerifier(Unknown Source)
at java.util.jar.JarFile.getInputStream(Unknown Source)
at sun.misc.URLClassPath$JarLoader.getInputStream(Unknown Source)
at sun.misc.Resource.cachedInputStream(Unknown Source)
at sun.misc.Resource.getByteBuffer(Unknown Source)
at java.net.URLClassLoader.defineClass(Unknown Source)
at java.net.URLClassLoader.access0(Unknown Source)
at java.net.URLClassLoader.run(Unknown Source)
at java.net.URLClassLoader.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)
at sun.launcher.LauncherHelper.checkAndLoadMain(Unknown Source)
采纳答案by Andrei R?nea
Well I should have built the JAR without the sqljdbc4.jar embedded.
好吧,我应该在没有嵌入 sqljdbc4.jar 的情况下构建 JAR。
The second thing I should have run the command like so :
第二件事我应该像这样运行命令:
java -classpath sqljdbc4.jar;cliTest.jar com.company.Main
.. and then all worked!
..然后一切正常!
回答by Nikolay
Use java -cp
instead of java -jar
and put all of you dependencies jars to classpath.
使用java -cp
代替java -jar
并将所有依赖项 jar 放入类路径。
Another way is pack all of dependencies to single jar, that allowing you to run application using java -jar
.
另一种方法是将所有依赖项打包到单个 jar 中,这样您就可以使用java -jar
.
EDIT:
编辑:
In Java *.jar file contains a bulk of classes. When you build your own app, typically, result jar file contains only your classes, but still have to load classes from external libraries you use (so-called dependencies).
在 Java 中 *.jar 文件包含大量的类。当您构建自己的应用程序时,通常,结果 jar 文件仅包含您的类,但仍必须从您使用的外部库(所谓的依赖项)加载类。
It can be done two different ways:
它可以通过两种不同的方式完成:
You create a folder for your application, for example, called
lib
and place your application jar and all dependencies into. Then you run application usingjava -cp lib:/\* com.company.Main
or (thanks @NilsH, I miss this variant) you makeMANIFEST.MF
file and specifyMain-Class
andClasspath
attributes inside as described hereYou use special tool (like maven-dependency-plugin if you use maven for build) to pack all classes, either your own, either external to single jar. You got one huge file and can run it using
java -jar cliTest.jar
.
您为您的应用程序创建一个文件夹,例如,调用
lib
并将您的应用程序 jar 和所有依赖项放入其中。然后你使用运行应用程序java -cp lib:/\* com.company.Main
或(感谢@NilsH,我错过这个变体)你让MANIFEST.MF
文件并指定Main-Class
与Classpath
所描述的属性里面点击这里您使用特殊工具(如 maven-dependency-plugin,如果您使用 maven 进行构建)来打包所有类,无论是您自己的类,还是单个 jar 的外部类。你有一个巨大的文件,可以使用
java -jar cliTest.jar
.
Generally, first approach is preferred and using a MANIFEST.MF
file is a good form.
通常,首选第一种方法,使用MANIFEST.MF
文件是一种很好的形式。
回答by neeraj tiwari
Well if you are using maven you could use maven-shade-plugin to include dependent jar's in executable jar the snippet of the pom.xml is given below.
好吧,如果您使用的是 maven,则可以使用 maven-shade-plugin 将依赖的 jar 包含在可执行 jar 中,下面给出了 pom.xml 的片段。
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <mainClass>com.main.class.YouMainClass</mainClass>
</transformer>
</transformers>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>