Hier ist, wie mein Code aussieht, und es ist unklar, wie / warum executorService.submit(work::get)
eine ClassNotFoundException
in die betreffende anonyme Klasse geworfen werden soll . Es kommt nicht immer vor, aber sobald diese Ausnahme auftritt, scheint sie nicht wiederhergestellt zu werden. Nachfolgende Anforderungen werden dann mit denselben Ausnahmen erfüllt. Weiß jemand, was dies verursachen könnte?
BEARBEITEN: Ich kann bestätigen, dass entweder alle Aufrufe dieser Methode funktionieren oder keiner in einer VM-Sitzung - es ist nicht so, dass einige erfolgreich sind, während andere aufgrund dieser Ausnahme fehlschlagen.
Weitere Bearbeitung: https://bugs.openjdk.java.net/browse/JDK-8148560 ist genau der Fehler, den ich habe, aber dieser wurde geschlossen, da er nicht reproduzierbar war und / oder der Reporter nicht antwortete. Es sieht irgendwie so aus, als ob der anonyme Typ, der aus dem Lambda-Ausdruck resultiert, Müll ist, der gesammelt wird, bevor der Executor den Ausdruck ausführen kann, aber offensichtlich nicht immer. Das verwendete JDK ist 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
}
}
So sieht die Ausnahme-Stacktrace aus (Zeilennummern stimmen nicht überein, da der obige Code nur ein Prototyp ist):
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
@Transactional
auch mit demtransactionTemplate
Inneren kommentieren zu lassen ?Antworten:
Dies ist der Fall bei einer von Lambda generierten Synthesemethode, die die erforderliche Klasse (dh TransactionCallback ) und damit den folgenden Fehler nicht finden kann
Der bestimmte Code, der dieses Problem verursacht, ist
Um dies zu umgehen, ändern Sie den Code wie folgt
Wenn oben immer noch nicht funktioniert, verwenden Sie die folgende Problemumgehung
Lassen Sie in Kommentaren wissen, ob weitere Informationen erforderlich sind.
PS: Es besteht keine Notwendigkeit,
@Transactional
wenn verwendettransactionTemplate
wird, da beide im Wesentlichen dem gleichen Zweck dienen.Verweise:
quelle
transactionTemplate
enthält diese Methode Wechselwirkungen, die die Standard verwenden@Transactional
Verhaltensweisen sowie diejenigen, die das benutzerdefinierte Vorlagenobjekt verwenden. Ich habe den ganzen Code der Kürze halber weggelassen.TransactionCallback
noch nicht geladen ist, wenn diese Methode die erste ist, die sie in einer bestimmten VM-Sitzung verwendet. Erklärt das das Verhalten?Ich hatte dies zuvor sowohl mit DI-Problemen als auch mit Mehrdeutigkeitsfehlern / Konfigurationsproblemen bei der Paketauflösung. Ich gehe von Ihrem Beitrag aus, dass der Fehler nach erfolgreichem Start und genau beim Aufruf dieser Zeile in der Methode auftritt und im Debugger getroffen werden kann.
Erster Vorschlag:
Überprüfen Sie mit Gradle / Maven abhängige Pakete, um sicherzustellen, dass alles die benötigte Version hat, und Sie überschreiben keine Version global, die sich auf ein abhängiges Paket auswirken kann, für das eine höhere oder niedrigere Version dieser Abhängigkeit erforderlich ist.
Einige niedrig hängende Früchte, die Sie zuerst probieren sollten (wenn es leicht genug ist, sie zu pflücken):
In Bezug auf die Abhängigkeitsinjektion,
Ich würde empfehlen, Folgendes zu versuchen. Dies ist auch eine gute Vorgehensweise für die Abhängigkeitsinjektion im Frühjahr, da Spring eine explizitere Abhängigkeitszuordnung erhält und Ihre Fähigkeit zum Debuggen der Anwendungsabhängigkeiten erhöht wird.
Es gibt einige Gründe, warum ich dies empfehle:
Da dies eine gültige Bean-Definition sein sollte, solange die Klasse im Komponentenscan Ihrer Konfiguration enthalten ist, müssen Sie die Bean möglicherweise explizit in einer Konfigurationsklasse definieren, insbesondere wenn Sie mehrere Beans jedes Typs haben (was auch Ihr Problem sein könnte )
Ex:
Beachten Sie, dass für die Konfiguration die Parameter für die Bean-Methode bis zum Frühjahr automatisch gesendet werden, sobald diese Beans in dieser Konfiguration oder einer anderen Konfiguration initialisiert wurden. Ziemlich cool, oder?
Auch der Name Ihrer Bean entspricht hier dem Methodennamen. Wenn Sie mehrere Beans desselben Typs haben, die spring als Parameter übergeben könnte, müssen Sie spring möglicherweise mitteilen, welcher Bean-Name verwendet werden soll. Verwenden Sie dazu die Annotation @Qualifier.
Ich hoffe wirklich, dass dies hilft oder zumindest bestätigt, dass die Instanziierung korrekt erfolgt.
quelle