应用程序中的 NoClassDefFoundError,类路径是正确的(乍一看)。为什么?
NoClassDefFoundError in app, classpath is correct (at first sight). Why?
I 运行 my app.jar as java -jar app.jar
并查看下一个错误:
Error: A JNI error has occurred, please check your installation and try again
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/thrift/transport/TTransportException
at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)
at java.lang.Class.privateGetMethodRecursive(Class.java:3048)
at java.lang.Class.getMethod0(Class.java:3018)
at java.lang.Class.getMethod(Class.java:1784)
at sun.launcher.LauncherHelper.validateMainClass(LauncherHelper.java:544)
at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:526)
Caused by: java.lang.ClassNotFoundException: org.apache.thrift.transport.TTransportException
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 7 more
app.jar结构:
.
├── lib
│ ├── ... (some *.jar files)
│ ├── libthrift-0.9.3.jar
│ └── ... (some *.jar files)
├── META-INF
│ ├── MANIFEST.MF
│ └── maven
│ └── groupId-name
│ └── artifactId-name
│ ├── pom.properties
│ └── pom.xml
└── ... *.class files of app
在 META-INF/MANIFEST.MF
中声明一个 classpath
为:
Class-Path: lib/libthrift-0.9.3.jar lib/...(other *.jar's from lib/ folder)
libthrift-0.9.3.jar结构:
.
├── META-INF
│ ├── LICENSE.txt
│ ├── MANIFEST.MF
│ └── NOTICE.txt
└── org
└── apache
└── ... some packages with files
├── transport
│ ├── ... some files
│ ├── TTransportException.class
│ └── ...
└── ...
如您所见,class org.apache.transport.TTransportException
存在并且必须在 运行 时间内可以访问。但是不要。为什么会这样?
首先:如果您没有使用任何特殊的 tools/frameworks(例如 spring-boot),默认情况下在 java 中,您不能在 jar 中包含 jar。
第二:清单文件中的条目(如 Class-Path: lib/libthrift-0.9.3.jar 等)引用的不是 jar 中的 jar,而是文件中的 jars罐子附近的系统。也就是说 运行 你的应用 java -jar app.jar
的文件结构应该是:
./
/libs --> all 3-d party jars here
app.jar
如果你想把所有东西都放在一个罐子里,一种变体是使用所谓的 'uber-jar' - 在这种情况下,所有 3-d 派对 类 都从他们的罐子中提取并打包连同你自己的 类 在一个罐子里。
例如对于maven构建可以使用Shade Plugin。
在打包 app.jar 时,只需将 external/3rd 派对库(如 libthrift-0.9.3.jar 放在名为 "lib" 的 folder/directory 中app.jar。让你Manifest条目保持不变。执行时,使用 java -cp 。 -jar app.jar。否则,就像 inigo 所说的那样,只需使用像 eclipse 这样的工具并将所有库打包到 jar 中。另一种选择是简单地从 thrift 等外部 jar 中提取所有 class 文件并将它们打包到您的 app.jar 中。在那种情况下,您可以 运行 随心所欲。
I 运行 my app.jar as java -jar app.jar
并查看下一个错误:
Error: A JNI error has occurred, please check your installation and try again
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/thrift/transport/TTransportException
at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)
at java.lang.Class.privateGetMethodRecursive(Class.java:3048)
at java.lang.Class.getMethod0(Class.java:3018)
at java.lang.Class.getMethod(Class.java:1784)
at sun.launcher.LauncherHelper.validateMainClass(LauncherHelper.java:544)
at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:526)
Caused by: java.lang.ClassNotFoundException: org.apache.thrift.transport.TTransportException
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 7 more
app.jar结构:
. ├── lib │ ├── ... (some *.jar files) │ ├── libthrift-0.9.3.jar │ └── ... (some *.jar files) ├── META-INF │ ├── MANIFEST.MF │ └── maven │ └── groupId-name │ └── artifactId-name │ ├── pom.properties │ └── pom.xml └── ... *.class files of app
在 META-INF/MANIFEST.MF
中声明一个 classpath
为:
Class-Path: lib/libthrift-0.9.3.jar lib/...(other *.jar's from lib/ folder)
libthrift-0.9.3.jar结构:
. ├── META-INF │ ├── LICENSE.txt │ ├── MANIFEST.MF │ └── NOTICE.txt └── org └── apache └── ... some packages with files ├── transport │ ├── ... some files │ ├── TTransportException.class │ └── ... └── ...
如您所见,class org.apache.transport.TTransportException
存在并且必须在 运行 时间内可以访问。但是不要。为什么会这样?
首先:如果您没有使用任何特殊的 tools/frameworks(例如 spring-boot),默认情况下在 java 中,您不能在 jar 中包含 jar。
第二:清单文件中的条目(如 Class-Path: lib/libthrift-0.9.3.jar 等)引用的不是 jar 中的 jar,而是文件中的 jars罐子附近的系统。也就是说 运行 你的应用 java -jar app.jar
的文件结构应该是:
./
/libs --> all 3-d party jars here
app.jar
如果你想把所有东西都放在一个罐子里,一种变体是使用所谓的 'uber-jar' - 在这种情况下,所有 3-d 派对 类 都从他们的罐子中提取并打包连同你自己的 类 在一个罐子里。
例如对于maven构建可以使用Shade Plugin。
在打包 app.jar 时,只需将 external/3rd 派对库(如 libthrift-0.9.3.jar 放在名为 "lib" 的 folder/directory 中app.jar。让你Manifest条目保持不变。执行时,使用 java -cp 。 -jar app.jar。否则,就像 inigo 所说的那样,只需使用像 eclipse 这样的工具并将所有库打包到 jar 中。另一种选择是简单地从 thrift 等外部 jar 中提取所有 class 文件并将它们打包到您的 app.jar 中。在那种情况下,您可以 运行 随心所欲。