首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Lambda - ClassNotFoundException

Lambda - ClassNotFoundException
EN

Stack Overflow用户
提问于 2019-10-23 20:46:19
回答 2查看 939关注 0票数 8

下面是我的代码是什么样子的,还不清楚executorService.submit(work::get)如何/为什么会在这个匿名类上抛出一个ClassNotFoundException。这种情况并不总是发生,但一旦遇到此异常,它似乎就不会恢复--随后的请求就会遇到相同的异常。有人知道是什么导致了这一切吗?

编辑:我可以确认,在VM会话中,对该方法的所有调用都可以工作,或者没有调用--这不像某些调用成功,而其他调用由于上述异常而失败。

进一步编辑:https://bugs.openjdk.java.net/browse/JDK-8148560正是我所遇到的错误,但是那个错误已经关闭了,因为它是不可复制的和/或记者没有回应。从某种程度上看,由lambda表达式产生的匿名类型是在执行器执行表达式之前收集的垃圾,但显然并不总是这样。正在使用的jdk是openjdk1.8.0_221

代码语言:javascript
复制
package com.ab.cde.ct.service.impl;

@Service
public class IngestionService {
    @Autowired private TransactionTemplate transactionTemplate;
    @Autowired private AsyncTaskExecutor executorService;

    @Transactional
    public void ingest(Data data) {
        Supplier<Optional<String>> work = () -> transactionTemplate.execute(s -> {
            // actual work on the data object, enclosed in a try/catch/finally
        });
        executorService.submit(work::get); // this is where the exception gets thrown
    }
}

下面是异常堆栈跟踪的样子(行nos )。因为上面的代码只是一个原型):

代码语言:javascript
复制
2019-10-23 19:11:35,267|[http-apr-26001-exec-10]|[B6AC864143092042BBB4A0876BB51EB6.1]|[]|[ERROR] web.error.ErrorServlet  [line:142] org.springframework.web.util.NestedServletException: Handler processing failed; nested exception is java.lang.NoClassDefFoundError: com/ab/cde/ct/service/impl/IngestionService$$Lambda$53
org.springframework.web.util.NestedServletException: Handler processing failed; nested exception is java.lang.NoClassDefFoundError: com/ab/cde/ct/service/impl/IngestionService$$Lambda$53
    at org.springframework.web.servlet.DispatcherServlet.triggerAfterCompletionWithError(DispatcherServlet.java:1275)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:951)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:867)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:951)
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:853)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:661)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:827)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
Caused by: java.lang.NoClassDefFoundError: com/ab/cde/ct/service/impl/IngestionService$$Lambda$53
    at com.ab.cde.ct.service.impl.IngestionService$$Lambda$53/812375226.get$Lambda(Unknown Source)
    at com.ab.cde.ct.service.impl.IngestionService.ingest(IngestionService.java:264)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:96)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:260)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:94)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
    at com.sun.proxy.$Proxy252.ingest(Unknown Source)
Caused by: java.lang.ClassNotFoundException: com.ab.cde.ct.service.impl.IngestionService$$Lambda$53
    at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1364)
    at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1185)
    ... 115 more
EN

回答 2

Stack Overflow用户

发布于 2019-10-24 08:30:30

这是由lambda生成的合成方法的情况,它无法找到所需的类(即TransactionCallback),因此出现以下错误

起因: com/ab/cde/ct/service/impl/IngestionService$$Lambda$53 at com.ab.cde.ct.service.impl.IngestionService$$Lambda$53/812375226.get$Lambda(Unknown Source)

导致此问题的特定代码是

代码语言:javascript
复制
Supplier<Optional<String>> work = () -> transactionTemplate.execute(s -> {
        // actual work on the data object, enclosed in a try/catch/finally
});

若要通过此操作,请修改代码如下

代码语言:javascript
复制
TransactionCallback<Optional<String>> callback = transactionStatus -> {
      // your processing goes here  
      return Optional.of("some value"); 
};

Supplier<Optional<String>> work = () -> transactionTemplate.execute(callback);

如果上面仍然不起作用,请使用下面的解决方法

代码语言:javascript
复制
Object callback = (TransactionCallback<Optional<String>>)transactionStatus -> {
     // your processing goes here     
     return Optional.of("some value");
};

Supplier<Optional<String>> work = () -> transactionTemplate.execute((TransactionCallback<Optional<String>>)callback);

如果需要更多的信息,请在评论中告知。

P.S.:如果将transactionTemplate用作本质上相同的用途,则不需要@Transactional

参考文献:

  1. Lambda编译这里这里
  2. java中的合成方法
票数 5
EN

Stack Overflow用户

发布于 2019-12-23 19:07:59

我以前也遇到过DI问题和包解决中的模糊bug/配置问题。我从您的帖子中假设,错误发生在成功启动之后,也就是在方法中调用该行时,并且可以在调试器中命中。

第一项建议:

使用Gradle/Maven时,请检查依赖包,以确保所有组件都有它需要的版本,并且您不会全局覆盖可能会影响到需要更高或更低版本的依赖项的依赖包的版本。

一些低挂水果可以先试一试(如果很容易摘的话):

  • 更新您的JDK版本或Java版本(或者查看您团队中的另一个开发人员是否有不同的版本,他们可以重复这个问题)
  • 更新您的spring版本(甚至是一个小版本)
  • 更新IDE
  • 添加日志并检查该问题是否可以在发布环境中再现。

关于依赖注入,

我建议尝试以下几种方法。它也是spring中的依赖注入的良好实践,因为它为spring提供了一个更显式的依赖映射,并提高了调试应用程序依赖关系的能力。

代码语言:javascript
复制
@Service
public class IngestionService {

    private TransactionTemplate transactionTemplate;
    private AsyncTaskExecutor executorService;

    public IngestionService(TransactionTemplate transactionTemplate, AsyncTaskExecutor executorService) {
         this.transactionTemplate = transactionTemplate;
         this.executorService = executorService;
    }

    @Transactional
    public void ingest(Data data) {
        Supplier<Optional<String>> work = () -> transactionTemplate.execute(s -> {
            // actual work on the data object, enclosed in a try/catch/finally
        });
        executorService.submit(work::get); // this is where the exception gets thrown
    }
}

我建议这样做有几个原因:

  1. 在java中,当未定义构造函数时,它意味着存在一个默认构造函数,编译器将为您生成一个构造函数。对于spring来说,这可能会让人感到困惑,同时也会降低性能。
  2. 定义这个构造函数显式地告诉Spring:我依赖于这两个依赖项,我也将其设置为Beans,这些Beans将是非空的,并在构造时完全解决。必须先初始化这些依赖项,然后传入它们,然后才能成为有效的对象。
  3. 这有助于调试,您可以在构造函数中设置一个断点并验证即将出现的内容。
  4. 如果您的bean设置存在依赖项的问题,Spring就会爆炸。spring堆栈跟踪并不总是最有用的,但它可以帮助您调试任何没有完全隔离和以正确方式声明依赖的bean的问题。
  5. 它允许您从Spring框架的角度(很难知道幕后发生了什么)和应用程序/域逻辑的角度消除注入问题的可能性。如果以后仍然为null,那么您就可以调试构造函数中传递的内容--这意味着它要么是空的,要么是后来被取消分配的,或者是一个模糊的问题,其中可能有两个定义,即使最终创建了多个executorServices,第一个创建的spring也会传递。

由于这应该是一个有效的bean定义,只要类包含在配置的组件扫描中,您可能需要在配置类中显式地定义bean,特别是如果您有每个类型的多个bean(这也可能是您的问题)

例如:

代码语言:javascript
复制
@Configuration
class SomeConfiguration {

    @Bean
    public IngestionService myIngestionServiceDefaultBeanNameChangeMe(TransactionTemplate transactionTemplateParamSentBySpringAutomaticallyChangeMyName, AsyncTaskExecutor executorServiceSentBySpringAutomaticallyChangeMyName) {
         return new IngestionService(transactionTemplateParamSentBySpringAutomaticallyChangeMyName, executorServiceSentBySpringAutomaticallyChangeMyName);
    }
}

注意,对于配置,bean方法的params将在spring之前自动发送,一旦这些bean在此配置或另一个配置中被初始化。很酷吧?

此外,bean的名称与这里的方法名称相对应,如果您有多个相同类型的bean,spring可以作为参数传入,您可能需要告诉spring要使用哪个bean名。要做到这一点,您可以使用@限定符注释。

我真的希望这有帮助,或者至少验证实例化是正确的。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58530775

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档