本文介紹了Quarkus純模式下的手動上下文傳播的處理方法,對大家解決問題具有一定的參考價值,需要的朋友們下面隨著小編來一起學習吧!
問題描述
我正在嘗試使上下文傳播在Quarkus純模式下工作。
以下代碼在JVM模式下按預期工作,但在本機模式下返回MDC value: null
。
正如預期的那樣,我的意思是:
對curl http://localhost:8080/thread-context
的響應是MDC value: from-thread-context
@Inject
ManagedExecutor managedExecutor;
@Inject
ThreadContext threadContext;
private final Supplier<String> mdcValueSupplier =
() -> "MDC value: " + MDC.get("foo") + "
";
@GET
@Path("thread-context")
public String get() throws ExecutionException, InterruptedException {
MDC.put("foo", "from-thread-context");
Supplier<String> ctxSupplier = threadContext.contextualSupplier(mdcValueSupplier);
return managedExecutor.supplyAsync(ctxSupplier).get();
}
我已經創建了一個github repo,其中包含演示應用的完整代碼和重現該問題的逐步說明。
存在依賴項io.quarkus:quarkus-smallrye-context-propagation
。
Quarkus版本:1.9.2
問:是我的代碼有問題,還是Quarkus有問題?
參考:Quarkus documentatin on context propagation
推薦答案
您的代碼基本上很好[1],Quarkus在這方面也很好–但有兩件事需要理解。
第一,您沒有執行任何類型的手動上下文傳播。您的代碼是意外運行的,因為Quarkus使用JBoss LogManager作為記錄器,并且它的MDC不是普通的ThreadLocal
,它是一個InheritableThreadLocal
。因此,它有時會傳播上下文本身。但這并不是可以依賴的。例如,如果您執行實時重新加載(通過稍微修改代碼并再次運行curl
),它也將停止在JVM模式下工作。
第二,上下文傳播的要點是將線程本地狀態從一個線程轉移到另一個線程,但這不是自動發生的。您可以通過調用相應的API自己執行該操作(即手動上下文傳播),也可以實現ThreadContextProvider
。
我簡要介紹了MDC API(http://www.slf4j.org/api/org/slf4j/MDC.html),似乎可以使用getCopyOfContextMap
和setContextMap
實現基本的上下文傳播。下面是我快速組裝的一個實現–注意,我沒有對代碼進行太多測試:
import org.eclipse.microprofile.context.spi.ThreadContextProvider;
import org.eclipse.microprofile.context.spi.ThreadContextSnapshot;
import org.slf4j.MDC;
import java.util.Map;
public class MdcContextProvider implements ThreadContextProvider {
@Override
public ThreadContextSnapshot currentContext(Map<String, String> props) {
Map<String, String> propagate = MDC.getCopyOfContextMap();
return () -> {
Map<String, String> old = MDC.getCopyOfContextMap();
MDC.setContextMap(propagate);
return () -> {
MDC.setContextMap(old);
};
};
}
@Override
public ThreadContextSnapshot clearedContext(Map<String, String> props) {
return () -> {
Map<String, String> old = MDC.getCopyOfContextMap();
MDC.clear();
return () -> {
MDC.setContextMap(old);
};
};
}
@Override
public String getThreadContextType() {
return "SLF4J MDC";
}
}
如果您創建的META-INF/services/org.eclipse.microprofile.context.spi.ThreadContextProvider
文件包含此類的完全限定名稱,則MDC傳播應該適用于您,即使是在本機中也是如此。
這樣做可能存在的一個問題是,無論您在新線程上對MDC
所做的任何更改都不會傳播回原始線程,因為SLF4J故意不提供對后備映射的訪問,它只分發副本。這對你來說可能沒問題,也可能不好。
[1]如果您將ManagedExecutor
提交給ManagedExecutor
,則Supplier
您的Supplier
不必將Supplier
提交給ManagedExecutor
,ManagedExecutor
會自動執行此操作。
這篇關于Quarkus純模式下的手動上下文傳播的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,