2017-01-24 5 views
2

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()) 
     ); 
+0

나는 당신이 어떻게 인자들을 매치시키는 지에 대한 개선점을 추가했다. 현재, 제네릭 타입 매개 변수에는 인수 매처에'erausre'를 추가해야하는 그러한 매처 만 존재하지만 1.6.7에서는 수정되었습니다. –

답변

0

: 같은

편집 개정 및 (라파엘의 도움으로) 코드를 작업 보인다 조언. 오히려 다음 유형의 상수를 사용하여 인수의 이름과 일치, 요소 매처 (matcher)에 관해서는

new AgentBuilder.Transformation.ForAdvice() 
    .include(getClass().getClassLoader()) 
    .advice("your.pkg.ServletAdvice") 

:이 문제를 극복하기 위해, 바이트 버디는 모두 사용자와 에이전트의 클래스 로더에 대한 조언 클래스를 해결하는 특정 변압기를 제공합니다.

+0

이 방법을 정규 인터셉터에 사용할 수 있습니까? 또는 '조언'에만 적용됩니까? –

+1

인터셉터는 인라인되지 않으므로 이러한 특성을 나타내지 않습니다. –