您的代码本质上很好 [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]如果您将其提交给您,则不必“上下文化”您Supplier
的-自动执行此操作。ThreadContext.contextualSupplier
ManagedExecutor
ManagedExecutor