下面是我的代码是什么样子的,还不清楚executorService.submit(work::get)如何/为什么会在这个匿名类上抛出一个ClassNotFoundException。这种情况并不总是发生,但一旦遇到此异常,它似乎就不会恢复--随后的请求就会遇到相同的异常。有人知道是什么导致了这一切吗?
编辑:我可以确认,在VM会话中,对该方法的所有调用都可以工作,或者没有调用--这不像某些调用成功,而其他调用由于上述异常而失败。
进一步编辑:https://bugs.openjdk.java.net/browse/JDK-8148560正是我所遇到的错误,但是那个错误已经关闭了,因为它是不可复制的和/或记者没有回应。从某种程度上看,由lambda表达式产生的匿名类型是在执行器执行表达式之前收集的垃圾,但显然并不总是这样。正在使用的jdk是openjdk1.8.0_221。
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 )。因为上面的代码只是一个原型):
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发布于 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)
导致此问题的特定代码是
Supplier<Optional<String>> work = () -> transactionTemplate.execute(s -> {
// actual work on the data object, enclosed in a try/catch/finally
});若要通过此操作,请修改代码如下
TransactionCallback<Optional<String>> callback = transactionStatus -> {
// your processing goes here
return Optional.of("some value");
};
Supplier<Optional<String>> work = () -> transactionTemplate.execute(callback);如果上面仍然不起作用,请使用下面的解决方法
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。
参考文献:
发布于 2019-12-23 19:07:59
我以前也遇到过DI问题和包解决中的模糊bug/配置问题。我从您的帖子中假设,错误发生在成功启动之后,也就是在方法中调用该行时,并且可以在调试器中命中。
第一项建议:
使用Gradle/Maven时,请检查依赖包,以确保所有组件都有它需要的版本,并且您不会全局覆盖可能会影响到需要更高或更低版本的依赖项的依赖包的版本。
一些低挂水果可以先试一试(如果很容易摘的话):
关于依赖注入,
我建议尝试以下几种方法。它也是spring中的依赖注入的良好实践,因为它为spring提供了一个更显式的依赖映射,并提高了调试应用程序依赖关系的能力。
@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
}
}我建议这样做有几个原因:
由于这应该是一个有效的bean定义,只要类包含在配置的组件扫描中,您可能需要在配置类中显式地定义bean,特别是如果您有每个类型的多个bean(这也可能是您的问题)
例如:
@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名。要做到这一点,您可以使用@限定符注释。
我真的希望这有帮助,或者至少验证实例化是正确的。
https://stackoverflow.com/questions/58530775
复制相似问题