![](/img/trans.png)
[英]How to intercept method with ByteBuddy as in CGLIB with MethodInterceptor for calling MethodProxy.invokeSuper(…)
[英]How to use ByteBuddy interceptor to replace CGLib?
我正在嘗試用 ByteBuddy 實現替換我的 CGLib 攔截器,但它不起作用。 在 CGLIB 中,我捕獲每個方法調用並將其發送到 ObjectProxy 中的一個方法。 我已經閱讀了這個和這個以及其他很多人,但它仍然不起作用。
這是我的代碼草稿:TestByteBuddy.java
import static java.lang.ClassLoader.getSystemClassLoader;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.description.modifier.Visibility;
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.matcher.ElementMatchers;
/**
*
* @author Marcelo D. Ré {@literal <marcelo.re@gmail.com>}
*/
public class TestByteBuddy {
private final static Logger LOGGER = Logger.getLogger(TestByteBuddy.class .getName());
static {
if (LOGGER.getLevel() == null) {
LOGGER.setLevel(Level.INFO);
}
}
public TestByteBuddy() {
System.out.println("Inite BB test...");
}
public void test() {
try {
Class<?> poClass = new ByteBuddy()
.subclass(BBFoo.class)
.defineField("___ogm___interceptor", ObjectProxy.class, Visibility.PUBLIC)
.implement(ITest.class)
.method(ElementMatchers.any()) // isDeclaredBy(ITest.class)
.intercept(MethodDelegation.toField("___ogm___interceptor")) // MethodDelegation.to(bbi)
.make()
.load(getSystemClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
.getLoaded();
// crear la instancia
BBFoo po = (BBFoo) poClass.newInstance();
// agregar el interceptor
ObjectProxy bbi = new ObjectProxy();
bbi.setInternalState("primer objeto");
poClass.getField("___ogm___interceptor").set(po, bbi);
// crear la instancia
BBFoo po2 = (BBFoo) poClass.newInstance();
// agregar el interceptor
ObjectProxy bbi2 = new ObjectProxy();
bbi2.setInternalState("segundo objeto");
poClass.getField("___ogm___interceptor").set(po2, bbi2);
// testear los objetos
System.out.println("*************************************");
System.out.println("invocar a setTestString....");
po.setTestString("Objeto 1");
po.sayHello();
System.out.println(""+po.testString);
((ITest)po).testCall();
((ITest)po).incValCall();
System.out.println("ObjectProxy InternalState: "+((ITest)po).getInternalState());
System.out.println("*************************************");
System.out.println("invocar a setTestString....");
po2.setTestString("Objeto 2");
po2.sayHello();
System.out.println(""+po.testString);
((ITest)po2).testCall();
((ITest)po2).incValCall();
System.out.println("ObjectProxy InternalState: "+((ITest)po2).getInternalState());
System.out.println("*************************************");
} catch (SecurityException ex) {
Logger.getLogger(TestByteBuddy.class.getName()).log(Level.SEVERE, null, ex);
} catch (NoSuchFieldException ex) {
Logger.getLogger(TestByteBuddy.class.getName()).log(Level.SEVERE, null, ex);
} catch (InstantiationException ex) {
Logger.getLogger(TestByteBuddy.class.getName()).log(Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
Logger.getLogger(TestByteBuddy.class.getName()).log(Level.SEVERE, null, ex);
}
}
public static void main(String[] args) {
new TestByteBuddy().test();
}
}
ObjectProxy.java
import java.lang.reflect.Method;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.bytebuddy.implementation.bind.annotation.AllArguments;
import net.bytebuddy.implementation.bind.annotation.Origin;
import net.bytebuddy.implementation.bind.annotation.RuntimeType;
import net.bytebuddy.implementation.bind.annotation.SuperMethod;
import net.bytebuddy.implementation.bind.annotation.This;
/**
*
* @author Marcelo D. Ré {@literal <marcelo.re@gmail.com>}
*/
public class ObjectProxy implements ITest {
private final static Logger LOGGER = Logger.getLogger(ObjectProxy.class .getName());
static {
if (LOGGER.getLevel() == null) {
LOGGER.setLevel(Level.INFO);
}
}
String internalState;
public ObjectProxy() {
}
@Override
public String getInternalState() {
return internalState;
}
@Override
public void setInternalState(String internalState) {
this.internalState = internalState;
}
@Override
public void testCall() {
System.out.println("ObjectProxy TestCall");
}
@Override
public int incValCall() {
System.out.println("ObjectProxy incValCall");
return 0;
}
// a este método se llama cuando se usa MethodDeletation
@RuntimeType
public Object intercept(@This Object self,
@Origin Method method,
@AllArguments Object[] args,
@SuperMethod Method superMethod) throws Throwable {
Object res = null;
System.out.println(">>>>>>>>> Intercepted: "+method.getName());
switch(method.getName()){
case "testCall":
System.out.println("intercept TestCall");
this.testCall();
break;
case "incValCall":
System.out.println("intercept incValCall");
this.incValCall();
break;
default:
System.out.println("intercept default: "+self.getClass().toString() +" : "+ superMethod.getName()+" : "+method.getName());
res = superMethod.invoke(self, args);
}
System.out.println("^^^^^^^^^^^^^^^^");
return res;
}
ITest.java
public interface ITest {
public void testCall();
public int incValCall();
public String getInternalState();
public void setInternalState(String internalState) ;
}
BBFoo.java
public class BBFoo {
private final static Logger LOGGER = Logger.getLogger(BBFoo.class .getName());
static {
if (LOGGER.getLevel() == null) {
LOGGER.setLevel(Level.INFO);
}
}
public String testString;
private int val = 0;
public void sayHello(){
System.out.println("Hola mundo! soy "+this.testString);
}
public int incVal() {
val++;
return val;
}
public void setTestString(String s) {
testString = s;
}
public String getTestString() {
return testString;
}
}
根據建議,我重新編輯了 TestByteBuddy.java,現在它看起來像這樣:
import static java.lang.ClassLoader.getSystemClassLoader;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.description.modifier.Visibility;
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.matcher.ElementMatchers;
/**
*
* @author Marcelo D. Ré {@literal <marcelo.re@gmail.com>}
*/
public class TestByteBuddy {
private final static Logger LOGGER = Logger.getLogger(TestByteBuddy.class .getName());
static {
if (LOGGER.getLevel() == null) {
LOGGER.setLevel(Level.INFO);
}
}
public TestByteBuddy() {
System.out.println("Inite BB test...");
}
private <T> T getProxyIntance(Class<T> c) {
T po = null;
try {
Class<?> poClass = new ByteBuddy()
.subclass(c)
.defineField("___ogm___interceptor", ObjectProxy.class, Visibility.PUBLIC)
.implement(ITest.class)
.method(ElementMatchers.any()) // isDeclaredBy(ITest.class)
.intercept(MethodDelegation // This.class,Origin.class,AllArguments.class,SuperMethod.class)
.withDefaultConfiguration() //.withBinders(TargetMethodAnnotationDrivenBinder.ParameterBinder.DEFAULTS)
.filter(ElementMatchers.named("intercept"))
.toField("___ogm___interceptor")) // MethodDelegation.to(bbi)
.make()
.load(getSystemClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
.getLoaded();
// crear la instancia
po = (T) poClass.newInstance();
// agregar el interceptor
ObjectProxy bbi = new ObjectProxy();
poClass.getField("___ogm___interceptor").set(po, bbi);
} catch (NoSuchFieldException | InstantiationException | IllegalAccessException ex) {
Logger.getLogger(TestByteBuddy.class.getName()).log(Level.SEVERE, null, ex);
}
return po;
}
public void test() {
try {
// crear la instancia
BBFoo po = this.getProxyIntance(BBFoo.class);
// crear la instancia
BBFoo po2 = this.getProxyIntance(BBFoo.class);
// testear los objetos
System.out.println("*************************************");
System.out.println("invocar a setTestString....");
po.setTestString("Objeto 1");
po.sayHello();
System.out.println(""+po.testString);
((ITest)po).testCall();
int i = ((ITest)po).incValCall();
System.out.println("ObjectProxy InternalState: "+((ITest)po).getInternalState());
System.out.println("*************************************");
System.out.println("invocar a setTestString....");
po2.setTestString("Objeto 2");
po2.sayHello();
System.out.println(""+po.testString);
((ITest)po2).testCall();
i = ((ITest)po2).incValCall();
System.out.println("ObjectProxy InternalState: "+((ITest)po2).getInternalState());
System.out.println("*************************************");
BBFooEx poEx = this.getProxyIntance(BBFooEx.class);
BBFooExEx poExEx = this.getProxyIntance(BBFooExEx.class);
} catch (SecurityException ex) {
Logger.getLogger(TestByteBuddy.class.getName()).log(Level.SEVERE, null, ex);
}
}
public static void main(String[] args) {
new TestByteBuddy().test();
}
}
並且我必須在ObjectProxy.java中的每個方法中添加@IgnoreForBinding
注釋,除了intercept
。
但是現在,如果我再添加這兩個 class,它會失敗:BBFooEx.java
public class BBFooEx extends BBFoo {
private final static Logger LOGGER = Logger.getLogger(BBFooEx.class .getName());
static {
if (LOGGER.getLevel() == null) {
LOGGER.setLevel(Level.INFO);
}
}
private String svex;
public BBFooEx() {
this(null, "default");
}
public BBFooEx(String s, String svex) {
super(s);
this.svex = svex;
}
public HashMap<String, String> hmString;
public HashMap<String, BBFooEx> ohmSVE;
public void initHashMapString() {
this.hmString = new HashMap<>();
this.hmString.put("hmString 1", "hmString 1");
this.hmString.put("hmString 1", "hmString 2");
this.hmString.put("hmString 1", "hmString 3");
}
}
BBFooExEx.java
public class BBFooExEx extends BBFooEx {
private final static Logger LOGGER = Logger.getLogger(BBFooExEx.class .getName());
static {
if (LOGGER.getLevel() == null) {
LOGGER.setLevel(Level.INFO);
}
}
public BBFooExEx() {
ohmSVE = new HashMap<>();
initHashMapString();
}
}
當 ByteBuddy 嘗試實例化 BBFooExEx 時,它失敗並出現 NullPointerException:
Exception in thread "main" java.lang.NullPointerException
at bb.BBFooExEx$ByteBuddy$bUrgo9zW.initHashMapString(Unknown Source)
at bb.BBFooExEx.<init>(BBFooExEx.java:26)
at bb.BBFooExEx$ByteBuddy$bUrgo9zW.<init>(Unknown Source)
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490)
at java.base/java.lang.Class.newInstance(Class.java:584)
at bb.TestByteBuddy.getProxyIntance(TestByteBuddy.java:50)
at bb.TestByteBuddy.test(TestByteBuddy.java:110)
有時您可能針對錯誤的方法。 使用:MethodDelegation.withDefaultConfiguration().filter(named("intercept")).toField(...)
這樣,您可以確保 Byte Buddy 僅嘗試您的目標方法。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.