具有默认访问权限的类在Spring Boot Project for Java 11中在运行时导致NoClassDefFound错误 [英] Classes with default access result in NoClassDefFound error at runtime in spring boot project for java 11
问题描述
我有一个使用Java 11的spring-boot项目.该项目依赖于redis,因此我在pom.xml中包含了spring-boot-starter-data-redis依赖关系.spring-data-redis jar中有一个名为JedisClientUtils的类,该类在类级别具有默认的访问修饰符.
I have a spring-boot project with Java 11. Project has dependency on redis, so I included spring-boot-starter-data-redis dependency in pom.xml. The spring-data-redis jar has a Class named JedisClientUtils which has a default access modifier at class level.
当我使用mvn spring-boot:run运行该项目时,我收到JedisClientUtils类的错误NoClassDefFound错误.在调试问题时,我发现使用Java 8时,同一项目成功运行.我的pom.xml具有如下插件:
When I run this project using mvn spring-boot:run, I get an error NoClassDefFound error for JedisClientUtils class. While debugging the issue I found that the same project runs successfully while using Java 8. My pom.xml has plugin as follows:
<build>
<finalName>${war.name}</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>11</source>
<target>11</target>
</configuration>
<dependencies>
<dependency>
<!-- update compiler plugin dependency on ASM for Java 11 compatibility -->
<groupId>org.ow2.asm</groupId>
<artifactId>asm</artifactId>
<version>6.2</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
使用默认访问类构建Java 11项目是否还有其他要求?日志以供参考:
Is there anything else required to build a java 11 project with default access classes Logs for reference :
java.lang.reflect.InvocationTargetException在jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(本机方法)处在jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)在jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)在java.lang.reflect.Method.invoke(Method.java:566)在org.springframework.boot.maven.AbstractRunMojo $ LaunchRunner.run(AbstractRunMojo.java:558)在java.lang.Thread.run(Thread.java:834)造成原因:java.lang.NoClassDefFoundError:无法初始化类org.springframework.data.redis.connection.jedis.JedisClientUtils在org.springframework.data.redis.connection.jedis.JedisConnection.isQueueing(JedisConnection.java:339)
java.lang.reflect.InvocationTargetException at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0 (Native Method) at jdk.internal.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62) at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke (Method.java:566) at org.springframework.boot.maven.AbstractRunMojo$LaunchRunner.run (AbstractRunMojo.java:558) at java.lang.Thread.run (Thread.java:834) Caused by: java.lang.NoClassDefFoundError: Could not initialize class org.springframework.data.redis.connection.jedis.JedisClientUtils at org.springframework.data.redis.connection.jedis.JedisConnection.isQueueing (JedisConnection.java:339)
spring-boot-data-redis版本:2.1.1发布jedis.version:2.9.0
spring-boot-data-redis verison : 2.1.1.RELEASE jedis.version : 2.9.0
推荐答案
您可以配置ForkJoinPool的线程工厂来设置您希望在应用程序范围内使用的类加载器,而不是每次运行任务时都设置上下文类加载器.参见 CompletableFuture/ForkJoinPool设置类加载器(不肮脏的答案).
You COULD configure the ForkJoinPool's thread factory to set the classloader you expect application wide instead of setting the context Classloader every time a task is run. See CompletableFuture / ForkJoinPool Set Class Loader (The non dirty answer).
一个警告是,这一突破性变化似乎是由以下主张引起的:人们不能依赖应用程序生命周期中特定时刻的公共池初始化线程(例如,可以在类加载器初始化您的公共加载器之前初始化公共池线程).春天的应用程序已创建).
One caveat is that this breaking change seems to have been prompted by the assertion that one cannot rely on the common pool initializing threads at a particular point in the application's lifecycle (eg. common pool threads could be initialized before the classloader initializing your spring application is created).
特别是对于Spring应用程序,鉴于Java 9中引入的重大更改以及缺乏保证将使用classloader初始化公共池的保证,因此配置自定义的ForkJoinPool并向其提交任务而不是依赖commonPool似乎是明智的选择.即使使用定制工厂,您的spring应用程序也需要.像这样:
For Spring apps specifically it seems prudent to configure a custom ForkJoinPool and submit tasks to that instead of relying on the commonPool given the breaking change introduced in Java 9 and the lack of a guarantee that the common pool will be initialized with the classloader your spring application needs even with a custom factory. Something like:
@Bean
public ForkJoinPool myForkJoinPool() {
int threads = Runtime.getRuntime().availableProcessors();
return new ForkJoinPool(threads, makeFactory("MyFactory"), null, false);
}
private ForkJoinWorkerThreadFactory makeFactory(String prefix) {
return pool -> {
final ForkJoinWorkerThread worker = ForkJoinPool.defaultForkJoinWorkerThreadFactory.newThread(pool);
worker.setName(prefix + worker.getPoolIndex());
worker.setContextClassLoader(Application.class.getClassLoader());
return worker;
};
}
将您的池注入执行并行操作的组件中并在其中调用:
Where your pool is injected into components performing parallel operations, and is invoked:
myForkJoinPool.submit(myTask)
这篇关于具有默认访问权限的类在Spring Boot Project for Java 11中在运行时导致NoClassDefFound错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!