具有默认访问权限的类在Spring Boot Project for Java 11中在运行时导致NoClassDefFound错误 [英] Classes with default access result in NoClassDefFound error at runtime in spring boot project for java 11

查看:69
本文介绍了具有默认访问权限的类在Spring Boot Project for Java 11中在运行时导致NoClassDefFound错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个使用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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆