Byte Buddy 기반의 Java 에이전트를 사용하여 javax.servlet.http.HttpServlet의 service() 메소드에 대한 호출을 계측하려고합니다. 내 코드에서 모두 premain 기능이 제대로이라고하지만 장비는 스택 추적에 실패 :byte-buddy throw java.lang.ClassNotFoundException : javax.servlet.http.HttpServlet
AgentBuilder b = new AgentBuilder.Default().ignore(ElementMatchers.none())
.with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION)
.with(AgentBuilder.InitializationStrategy.NoOp.INSTANCE)
.with(AgentBuilder.TypeStrategy.Default.REDEFINE)
.type(ElementMatchers.isSubTypeOf(HttpServlet.class))
.transform((builder, type, classLoader) ->
builder.visit(Advice.to(ServletAdvice.class)
.on(ElementMatchers.named("service")
.and(ElementMatchers.takesArgument(0, HttpServletRequest.class))
.and(ElementMatchers.takesArgument(1, HttpServletResponse.class)))).installOn(inst);
을 그리고 내 조언 구현은 다음과 같습니다 :
public class ServletAdvice {
@Advice.OnMethodEnter
public static void before(@Advice.This Object obj,
@Advice.Argument(value = 0) HttpServletRequest a1,
@Advice.Argument(value = 1) HttpServletResponse a2,
@Advice.Origin Method method)
{
System.out.println("\nRunning pre-method logic for " + obj.getClass().getCanonicalName() + ":" + method.getName() + "()");
<...etc...>
}
}
}
다음과 같이
java.lang.reflect.InvocationTargetException
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 sun.instrument.InstrumentationImpl.loadClassAndStartAgent(InstrumentationImpl.java:386)
at sun.instrument.InstrumentationImpl.loadClassAndCallPremain(InstrumentationImpl.java:401)
Caused by: java.lang.NoClassDefFoundError: javax/servlet/http/HttpServlet
at ub.jagent.ServletInstrumentation.instrument(ServletInstrumentation.java:24)
at ub.jagent.StackTracerAgent.premain(StackTracerAgent.java:75)
... 6 more
Caused by: java.lang.ClassNotFoundException: javax.servlet.http.HttpServlet
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 8 more
FATAL ERROR in native method: processing of -javaagent failed
내가 에이전트 빌더를 사용하여
이상하게도 특정 Tomcat 구현 클래스와 일치 할 때 :
.type(ElementMatchers.named("org.glassfish.jersey.servlet.ServletContainer"))
... 그러면 에이전트 설치가 작동합니다 (Advice 메소드의 HttpServletRequest 및 HttpServletResponse에 대한 참조는 계측 자체에서 ClassNotFoundException을 트리거합니다).
그렇다면 에이전트 .jar 파일 자체에 모든 에이전트 종속성 (Java Servlet API 포함)을 포함해야한다는 의미입니까?
ByteBuddy 1.6.2, Apache Tomcat v8.0을 사용하고 있습니다. 나는 유형의 서블릿 가족 바이트 버디 해결을 위해 사용하는 클래스 로더를 사용할 수없는 가정
.type(ElementMatchers.isSubTypeOf(new TypeDescription.Latent("javax.servlet.GenericServlet", Modifier.PUBLIC | Modifier.ABSTRACT, TypeDescription.Generic.OBJECT, null)))
.transform(
new AgentBuilder.Transformer.ForAdvice()
.include(getClass().getClassLoader())
.advice(
ElementMatchers.named("service")
.and(ElementMatchers.takesArgument(0, ElementMatchers.named("javax.servlet.http.HttpServletRequest"))
.and(ElementMatchers.takesArgument(1, ElementMatchers.named("javax.servlet.http.HttpServletResponse")),
ServletAdvice.class.getName())
);
나는 당신이 어떻게 인자들을 매치시키는 지에 대한 개선점을 추가했다. 현재, 제네릭 타입 매개 변수에는 인수 매처에'erausre'를 추가해야하는 그러한 매처 만 존재하지만 1.6.7에서는 수정되었습니다. –