为什么在 运行 作为 jar 时得到 java.lang.ClassNotFoundException,但与 IntelliJ IDEA 配合得很好
Why get java.lang.ClassNotFoundException when run as jar, but work well with IntelliJ IDEA
spring 引导版本:2.4.1
spring云版本:2020.0.0
我的代码
@Configuration
public class BaseConfig {
@Bean
public Module sortJacksonModule() {
return new SortJacksonModule();
}
}
我的pom.xml依赖关系
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-openfeign-core</artifactId>
</dependency>
我的pom.xml插件
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
当 运行 使用 IntelliJ IDEA 时,效果很好。
但是当运行用jar(by mvn clean package
)时,它显示
Caused by: java.lang.NoClassDefFoundError: feign/codec/EncodeException
at org.springframework.cloud.openfeign.support.SortJacksonModule.setupModule(SortJacksonModule.java:47) ~[spring-cloud-openfeign-core-3.0.0.jar!/:3.0.0]
at com.fasterxml.jackson.databind.ObjectMapper.registerModule(ObjectMapper.java:819) ~[jackson-databind-2.11.3.jar!/:2.11.3]
at com.fasterxml.jackson.databind.ObjectMapper.registerModules(ObjectMapper.java:1021) ~[jackson-databind-2.11.3.jar!/:2.11.3]
at org.springframework.http.converter.json.Jackson2ObjectMapperBuilder.configure(Jackson2ObjectMapperBuilder.java:712) ~[spring-web-5.3.2.jar!/:5.3.2]
at org.springframework.http.converter.json.Jackson2ObjectMapperBuilder.build(Jackson2ObjectMapperBuilder.java:680) ~[spring-web-5.3.2.jar!/:5.3.2]
at org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration$JacksonObjectMapperConfiguration.jacksonObjectMapper(JacksonAutoConfiguration.java:101) ~[spring-boot-autoconfigure-2.4.1.jar!/:2.4.1]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_232]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_232]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_232]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_232]
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154) ~[spring-beans-5.3.2.jar!/:5.3.2]
... 113 common frames omitted
Caused by: java.lang.ClassNotFoundException: feign.codec.EncodeException
at java.net.URLClassLoader.findClass(URLClassLoader.java:382) ~[na:1.8.0_232]
at java.lang.ClassLoader.loadClass(ClassLoader.java:418) ~[na:1.8.0_232]
at org.springframework.boot.loader.LaunchedURLClassLoader.loadClass(LaunchedURLClassLoader.java:151) ~[demo-spring-core-11-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT]
at java.lang.ClassLoader.loadClass(ClassLoader.java:351) ~[na:1.8.0_232]
... 124 common frames omitted
研究错误日志后,我发现 feign.codec.EncodeException
是 spring-cloud-openfeign-core
中的可选依赖项,因此 ClassNotFoundException 是正确的行为(可选依赖项不包含在最终 jar 中)。
所以我的问题是:为什么 IntelliJ IDEA 可以 运行 没有任何错误?我尝试了 IntelliJ IDEA 运行 和 mvn spring-boot:运行,两者都工作正常。
更新:添加示例
经过更多研究,我发现只有在 class 未调用时才会发生这种情况。
try {
System.out.println("not important code");
} catch (Exception e) {
throw new EncodeException("not exist class");
}
在此示例中,try catch 从未抛出异常。 EncodeException
class 是一个可选的依赖项。
此代码 运行 在 IntelliJ IDEA 中运行良好,但当 运行 为 java -jar xxx.jar
时失败
==========再次更新最小演示
我创建了一个最小演示来重现这个问题。
- 一个独立的演示模块
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-core</artifactId>
<version>10.10.1</version>
<optional>true</optional>
</dependency>
import feign.codec.EncodeException;
/**
* Hello world!
*/
public class App {
public void testOptional() {
try {
System.out.println("test");
} catch (Exception e) {
throw new EncodeException("never throw this");
}
}
}
- demo spring项目(由
spring initializr
创建并添加依赖项)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.example</groupId>
<artifactId>demo-module</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
@Component
public class MyMain implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
new App().testOptional();
}
}
检查您的项目 classIdea 中的路径 ( CTRL-Alt-Shift-S ) - 我敢说可选的 jar 位于模块编译 classpath 的某处并且足以 运行 IDE 中的 class - 但不在独立的 jar 中。可选意味着在 Maven 上下文中它在编译时出现在 class 路径上,但没有打包到生成的工件中。
在 IntelliJ IDEA 运行 配置中有一个名为 Enable launch optimization
的选项,取消选中它,一切都会按预期工作。
spring 引导版本:2.4.1
spring云版本:2020.0.0
我的代码
@Configuration
public class BaseConfig {
@Bean
public Module sortJacksonModule() {
return new SortJacksonModule();
}
}
我的pom.xml依赖关系
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-openfeign-core</artifactId>
</dependency>
我的pom.xml插件
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
当 运行 使用 IntelliJ IDEA 时,效果很好。
但是当运行用jar(by mvn clean package
)时,它显示
Caused by: java.lang.NoClassDefFoundError: feign/codec/EncodeException
at org.springframework.cloud.openfeign.support.SortJacksonModule.setupModule(SortJacksonModule.java:47) ~[spring-cloud-openfeign-core-3.0.0.jar!/:3.0.0]
at com.fasterxml.jackson.databind.ObjectMapper.registerModule(ObjectMapper.java:819) ~[jackson-databind-2.11.3.jar!/:2.11.3]
at com.fasterxml.jackson.databind.ObjectMapper.registerModules(ObjectMapper.java:1021) ~[jackson-databind-2.11.3.jar!/:2.11.3]
at org.springframework.http.converter.json.Jackson2ObjectMapperBuilder.configure(Jackson2ObjectMapperBuilder.java:712) ~[spring-web-5.3.2.jar!/:5.3.2]
at org.springframework.http.converter.json.Jackson2ObjectMapperBuilder.build(Jackson2ObjectMapperBuilder.java:680) ~[spring-web-5.3.2.jar!/:5.3.2]
at org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration$JacksonObjectMapperConfiguration.jacksonObjectMapper(JacksonAutoConfiguration.java:101) ~[spring-boot-autoconfigure-2.4.1.jar!/:2.4.1]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_232]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_232]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_232]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_232]
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154) ~[spring-beans-5.3.2.jar!/:5.3.2]
... 113 common frames omitted
Caused by: java.lang.ClassNotFoundException: feign.codec.EncodeException
at java.net.URLClassLoader.findClass(URLClassLoader.java:382) ~[na:1.8.0_232]
at java.lang.ClassLoader.loadClass(ClassLoader.java:418) ~[na:1.8.0_232]
at org.springframework.boot.loader.LaunchedURLClassLoader.loadClass(LaunchedURLClassLoader.java:151) ~[demo-spring-core-11-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT]
at java.lang.ClassLoader.loadClass(ClassLoader.java:351) ~[na:1.8.0_232]
... 124 common frames omitted
研究错误日志后,我发现 feign.codec.EncodeException
是 spring-cloud-openfeign-core
中的可选依赖项,因此 ClassNotFoundException 是正确的行为(可选依赖项不包含在最终 jar 中)。
所以我的问题是:为什么 IntelliJ IDEA 可以 运行 没有任何错误?我尝试了 IntelliJ IDEA 运行 和 mvn spring-boot:运行,两者都工作正常。
更新:添加示例
经过更多研究,我发现只有在 class 未调用时才会发生这种情况。
try {
System.out.println("not important code");
} catch (Exception e) {
throw new EncodeException("not exist class");
}
在此示例中,try catch 从未抛出异常。 EncodeException
class 是一个可选的依赖项。
此代码 运行 在 IntelliJ IDEA 中运行良好,但当 运行 为 java -jar xxx.jar
==========再次更新最小演示
我创建了一个最小演示来重现这个问题。
- 一个独立的演示模块
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-core</artifactId>
<version>10.10.1</version>
<optional>true</optional>
</dependency>
import feign.codec.EncodeException;
/**
* Hello world!
*/
public class App {
public void testOptional() {
try {
System.out.println("test");
} catch (Exception e) {
throw new EncodeException("never throw this");
}
}
}
- demo spring项目(由
spring initializr
创建并添加依赖项)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.example</groupId>
<artifactId>demo-module</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
@Component
public class MyMain implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
new App().testOptional();
}
}
检查您的项目 classIdea 中的路径 ( CTRL-Alt-Shift-S ) - 我敢说可选的 jar 位于模块编译 classpath 的某处并且足以 运行 IDE 中的 class - 但不在独立的 jar 中。可选意味着在 Maven 上下文中它在编译时出现在 class 路径上,但没有打包到生成的工件中。
在 IntelliJ IDEA 运行 配置中有一个名为 Enable launch optimization
的选项,取消选中它,一切都会按预期工作。