我正在尝试实现一个 Java 代理,它可以很容易地添加到我们一些遗留服务的命令行中,以使用OpenTracing API启用分布式跟踪。到目前为止,我正在使用ByteBuddy
(1.9.12) 并在检测代码针对以下场景运行时点击:NoClassDefFoundErrors
- 在包中检测了一个类
java.util.concurrent
:找不到,GlobalTracer
因为 Java 代理仅在应用程序类路径中。我通过将包含跟踪 API 的 Java 代理添加到命令行上的引导类路径(仅限 Java 8)暂时解决了这个问题,但我希望能够以编程方式执行此操作。寻找正确的方法来做到这一点。(编辑:这是通过使用Boot-Class-Path
Java 代理的清单文件中的选项来解决的——只需输入 Java 代理 JAR 本身的文件名——没有路径。) - 检测自定义网络客户端类:在我的 Intercept 类(在字节码注入期间)的自定义网络包中找不到类,因为网络客户端包不在 Java 代理 JAR 中。我正在寻找“正确的方法”来高层次地构建事物以避免这种情况。
方案 2 的代码:
public class NettyAgentRule implements AgentRule {
public Iterable<? extends AgentBuilder> buildAgent(AgentBuilder agentBuilder) {
return Arrays.asList(agentBuilder
.type(hasSuperType(named("org.jboss.netty.bootstrap.Bootstrap")))
.transform((builder, typeDescription, classLoader, module) -> {
return builder.visit(Advice.to(NettyAgentRule.class).on(named("setPipelineFactory")));
}));
}
@Advice.OnMethodEnter
public static void enter(final @Advice.Origin String origin,
final @Advice.This Object thiz,
@Advice.Argument(value = 0, readOnly = false, typing = Assigner.Typing.DYNAMIC) Object parameter) {
parameter = NettyAgentIntercept.enter(thiz, parameter);
}
}
错误发生在 NettyAgentIntercept 类中,该类引用 Netty 类。
我研究了 OpenTracing 'contrib' SpecialAgent 如何处理这些场景,并且它有相当多的自定义类加载正在进行,这与它们的构建结构紧密耦合(JAR 中的 JAR 遵循命名约定)。如果可能的话,最好避免这种情况。
场景 2 中的示例异常堆栈:
java.lang.NoClassDefFoundError: org/jboss/netty/channel/ChannelPipelineFactory
2019-07-05 18:52:21,10613 at com.example.tracing.netty.NettyAgentIntercept.enter(NettyAgentIntercept.java:9)
2019-07-05 18:52:21,10613 at org.jboss.netty.bootstrap.Bootstrap.setPipelineFactory(Bootstrap.java:251)
2019-07-05 18:52:21,10616 at com.example.lib.util.net.NettyCore.<init>(NettyCore.java:176)
2019-07-05 18:52:21,10616 at com.example.lib.util.net.NetClient.getInstance(NetClient.java:125)
2019-07-05 18:52:21,10617 at com.example.lib.util.net.NetClient.getInstance(NetClient.java:147)
2019-07-05 18:52:21,10617 at com.example.lib.util.net.NetClient.getInstance(NetClient.java:55)
2019-07-05 18:52:21,10617 at com.example.component.Component.main(Component.java:155)
2019-07-05 18:52:21,10618 at com.example.lib.util.invoke.ComponentThread.run(ComponentThread.java:21)
我还按照建议尝试了以下代码
byte-buddy 抛出 java.lang.ClassNotFoundException: javax.servlet.http.HttpServlet
但它会导致同样的异常:
public Iterable<? extends AgentBuilder> buildAgent(AgentBuilder agentBuilder) {
return Arrays.asList(agentBuilder
.type(hasSuperType(named("org.jboss.netty.bootstrap.Bootstrap")))
.transform(new AgentBuilder.Transformer.ForAdvice()
.include(getClass().getClassLoader())
.advice(named("setPipelineFactory"),"com.example.tracing.netty.NettyAgentAdvice")
));
}
建议类在哪里
package com.example.tracing.netty;
import org.jboss.netty.bootstrap.ClientBootstrap;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.implementation.bytecode.assign.Assigner;
public class NettyAgentAdvice {
@Advice.OnMethodEnter
public static void enter(final @Advice.Origin String origin,
final @Advice.This Object thiz,
@Advice.Argument(value = 0, readOnly = false, typing = Assigner.Typing.DYNAMIC) Object parameter) {
parameter = enter(thiz, parameter);
}
public static ChannelPipelineFactory enter(Object thiz, Object returned) {
ChannelPipelineFactory pipelineFactory = (ChannelPipelineFactory) returned;
if (thiz instanceof ClientBootstrap) {
return () -> {
ChannelPipeline pipeline = pipelineFactory.getPipeline();
if (pipeline.get(TracingHandler.class) == null) {
pipeline.addLast("tracing", new TracingHandler());
}
return pipeline;
};
}
return pipelineFactory;
}
}