2017-01-24 2 views
2

Я пытаюсь вызвать вызовы метода service() javax.servlet.http.HttpServlet с использованием Java-агента на основе Byte Buddy. Функция premain в моем коде называется правильно, но приборы не удается с трассировки стека:byte-buddy throws java.lang.ClassNotFoundException: javax.servlet.http.HttpServlet

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 

я использую агента строитель следующим образом:

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); 

И моя реализация Advice выглядит следующим образом:

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...> 
     } 
    } 
} 

Странно, когда я соглашаюсь на конкретный класс реализации Tomcat:

.type(ElementMatchers.named("org.glassfish.jersey.servlet.ServletContainer")) 

... тогда работает настройка агента (хотя ссылки на HttpServletRequest и HttpServletResponse в методе Advice инициируют ClassNotFoundException во время самой инструментализации).

Означает ли это, что я должен включать все агенты-зависимые (в том числе Java Servlet API) в самом файле .jar агента?

Я использую ByteBuddy 1.6.2, Apache Tomcat v8.0.

EDIT Пересмотренный и рабочий код (с помощью Рафаэля) выглядит следующим образом:

  .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

Я предполагаю, что сервлет-семейство типов не доступен загрузчик классов, который Byte Buddy использует для разрешения совет. Чтобы преодолеть это, Byte Buddy предлагает конкретный трансформатор, устраняющее класс советов как для пользователя и загрузчика класса агента:

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

Что касается элементов matchers, а совпадают имена аргументов, а затем с помощью констант типа.

+0

Можно ли использовать этот подход на регулярных перехватчиках? Или это применимо только к «Совету»? –

+1

Перехватчики не встроены, поэтому они не показывают этих характеристик. –

Смежные вопросы