这是我的代码的样子,目前尚不清楚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
}
}
这是异常堆栈跟踪的样子(行号不会对应,因为上面的代码只是一个原型):
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
答案 0 :(得分:5)
这是lambda生成的综合方法的情况,该方法无法找到所需的类(即TransactionCallback),因此找不到以下错误
原因:java.lang.NoClassDefFoundError:com / ab / cde / ct / service / impl / IngestionService $$ Lambda $ 53 com.ab.cde.ct.service.impl.IngestionService $$ Lambda $ 53 / 812375226.get $ Lambda(来源不明)
导致此问题的特定代码是
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。:如果使用@Transactional
则transactionTemplate
是不必要的,因为两者本质上是出于相同的目的。
参考文献:
答案 1 :(得分:0)
我以前遇到过DI问题和软件包解析中的歧义错误/配置问题。我从您的帖子中假设,错误是在成功启动后发生的,并且恰好是在方法中调用该行时发生的,并且可以在调试器中被击中。
第一个建议:
使用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,bean方法的参数将由spring自动发送。太酷了吗?
另外,您的bean的名称与此处的方法名称相对应,并且如果您有多个相同类型的bean,则spring可以作为参数传递,您可能需要告诉spring使用哪个bean名称。为此,您可以利用@Qualifier批注。
我真的希望这会有所帮助,或者至少验证实例化是否正确进行。