2015-12-23 26 views
6

Ben ÖNCE yapıcı önleme nasıl oluşturulacağını biliyor Bununla birlikte, bir önceki/sonraki önleyicinin nasıl oluşturulacağını bilmiyorum.sonra ve yapıcı interceptor önce

return builder.constructor(isDeclaredBy(typeDescription)) 
    .intercept(MethodDelegation.to(constructorInterceptor)); 

bu yöntem temsilci olarak:: İşte (zaten yöntemleri için çalıştı dayalı naif bir yaklaşım) çalıştı budur Bu kurulumla

public void intercept(@Origin Constructor<?> constructor, @SuperCall Callable<?> zuper) throws Exception { 
    System.out.println("before " + constructor.getName()); 

    zuper.call(); 

    System.out.println("after " + constructor.getName()); 
} 

alıyorum:

java.lang.ClassFormatError: Bad method name at constant pool index 23 in class file com/flow/agent/test/Foo$auxiliary$syFGNB3u 

Tam yığın izleme:

java.lang.IllegalStateException: Error invoking java.lang.ClassLoader#findClass 
    at net.bytebuddy.dynamic.loading.ClassInjector$UsingReflection$Dispatcher$Resolved.loadClass(ClassInjector.java:392) 
    at net.bytebuddy.dynamic.loading.ClassInjector$UsingReflection.inject(ClassInjector.java:201) 
    at net.bytebuddy.agent.builder.AgentBuilder$InitializationStrategy$SelfInjection$Dispatcher$Split.register(AgentBuilder.java:1017) 
    at net.bytebuddy.agent.builder.AgentBuilder$Default$Transformation$Simple$Resolution.apply(AgentBuilder.java:2795) 
    at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.transform(AgentBuilder.java:3081) 
    at sun.instrument.TransformerManager.transform(TransformerManager.java:188) 
    at sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:428) 
    at java.lang.ClassLoader.defineClass1(Native Method) 
    at java.lang.ClassLoader.defineClass(ClassLoader.java:760) 
    at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142) 
    at java.net.URLClassLoader.defineClass(URLClassLoader.java:467) 
    at java.net.URLClassLoader.access$100(URLClassLoader.java:73) 
    at java.net.URLClassLoader$1.run(URLClassLoader.java:368) 
    at java.net.URLClassLoader$1.run(URLClassLoader.java:362) 
    at java.security.AccessController.doPrivileged(Native Method) 
    at java.net.URLClassLoader.findClass(URLClassLoader.java:361) 
    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) 
    ... 
Caused by: java.lang.ClassFormatError: Bad method name at constant pool index 23 in class file com/flow/agent/test/Foo$auxiliary$syFGNB3u 
    at java.lang.ClassLoader.defineClass1(Native Method) 
    at java.lang.ClassLoader.defineClass(ClassLoader.java:760) 
    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:497) 
    at net.bytebuddy.dynamic.loading.ClassInjector$UsingReflection$Dispatcher$Resolved.loadClass(ClassInjector.java:388) 

cevap

2

Java sanal makinesinin doğrulayıcı, uygulanan herhangi bir kurucudan başka bir kurucunun kodlu çağrılmasını gerektirir. Bu nedenle, yaklaşık-tavsiyenin uygulanması için @SuperCall kullanılması maalesef işe yaramaz. Nitekim, @SuperCall ek açıklaması, kurucularla birlikte çalışamaz. (İdeal olarak, Byte Buddy kütüphanenin sonraki sürümü için o çözecektir bu girişimi yakalamak ve daha okunabilir bir istisnayı teşkil atardı.) Ne yapabilirsiniz

aşağıdaki gibi önleme tanımlamaktır:

public class Interceptor { 
    public void before(@Origin Constructor<?> constructor) { 
    System.out.println("before " + constructor.getName()); 
    } 
    public void after(Origin Constructor<?> constructor) { 
    System.out.println("after " + constructor.getName()); 
    } 
} 
böyle bir müdahaleyi kullanarak

: Bu, ilk before yöntemi çağırmak olacaktır

MethodDelegation.to(constructorInterceptor).filter(named("before")) 
       .andThen(SuperMethodCall.INSTANCE 
       .andThen(MethodDelegation.to(constructorInterceptor)) 
             .filter(named("after"))) 

sonra süper kurucusunu çağırmak ve sonra after önleme çağırmak. Tabii

, sen before den after bir değer taşımak mümkün isteyebilirsiniz. Bu amaçla, Byte Buddy henüz bir şeyler yapmanın harika bir yolunu sunmuyor. (Ben hala JVM'nin kendisinden faydalanmak için bir geliştirmeyi ümit ediyorum. Bu VM sınırlaması aynı zamanda metod tutamaçlarını kullanan kişilere de isabet ediyor ve genellikle VM ile çalışan insanlar tarafından talihsiz bir dezavantaj olarak bahsediliyor.)

Şimdilik her zaman alanını adresinde sırasında okuduğunuz bir değerde sakladığınız bir ara yüzde tanımlayın. (Tek bir iş parçacığı ortamında, ThreadLocal'u bile bırakabilir ve basit bir alan kullanabilirsiniz.) Bunu henüz hedeflemediğim bir nedenden dolayı, çoğu kurucu müdahalesinin, eklenme gerektirmemesidir. Daha ayrıntılı bir kullanım durumu belirtirseniz, size daha fazla yardımcı olabilirim.