2017-01-11 79 views
1

我期待在從別人一些ByteBuddy代碼的過程中使用截獲新定義的字段。他使用ByteBuddy生成運行時子類,這些子類用作代理來實現其運行時的某些管理代碼到特定對象中。ByteBuddy:建築

Class<? extends T> newSubClass = new ByteBuddy(ClassFileVersion.ofThisVm()) 
       .subclass(classType) 
       .defineField("_core", Object.class, Visibility.PUBLIC) //<--- 
       .method(ElementMatchers.isDeclaredBy(classType)) 
       .intercept(InvocationHandlerAdapter.of((proxy, method, m_args) -> { 
        //TODO: Need to replace core with _core as core is a function argument and will make it bound 
        return proxyHandler(core, method, m_args); //<-- 
       })) 
       .make() 
       .load(roleType.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER) 
       .getLoaded(); 


T proxy = ReflectionHelper.newInstance(newSubClass, args); 
newSubClass.getField("_core").set(proxy, core); 

爲了不core對象直接結合進欲使用新定義的字段_core所以可以重複使用生成的類(而不是重新生成它的函數的每個調用)拉姆達。 有沒有辦法做到這一點?

在此先感謝。

回答

1

您可以像定義方法一樣定義自定義構造函數。定義構造函數的一個重點是你需要另一個構造函數調用作爲它的第一條指令。您可以使用MethodCall::invoke調用構造函數,您可以將其與FieldAccessor::ofField結合使用。

這樣,您就可以定義類似類以下內容:

new ByteBuddy(ClassFileVersion.ofThisVm()) 
    .subclass(classType, ConstructorStrategy.Default.NO_CONSTRUCTORS) 
    .defineConstructor(Visibility.PUBLIC) 
    .withParameter(InvocationHandler.class) 
    .intercept(MethodCall.invoke(classType.getDeclaredConstructor()) 
    .andThen(FieldAccessor.ofField("_core").setsArgumentAt(0))) 
    .defineField("_core", InvocationHandler.class, Visibility.PUBLIC) 
    .method(ElementMatchers.isDeclaredBy(classType)) 
    .intercept(InvocationHandlerAdapter.toField("_core")) 
    .make(); 

這種方式,您可以設置每個實例的自定義InvocationHandler。如果你希望只存儲在_core場的狀態,並從你的攔截器訪問這個領域,看看MethodDelegation

new ByteBuddy(ClassFileVersion.ofThisVm()) 
    .subclass(classType, ConstructorStrategy.Default.NO_CONSTRUCTORS) 
    .defineConstructor(Visibility.PUBLIC) 
    .withParameter(Object.class) 
    .intercept(MethodCall.invoke(classType.getDeclaredConstructor()) 
    .andThen(FieldAccessor.ofField("_core").setsArgumentAt(0))) 
    .defineField("_core", Object.class, Visibility.PUBLIC) 
    .method(ElementMatchers.isDeclaredBy(classType)) 
    .intercept(MethodDelegation.to(MyHandler.class)) 
    .make(); 

public class MyHandler { 
    @RuntimeType 
    public static Object intercept(@FieldValue("_core") Object value) { ... } 
} 

你可能需要其他的註解是@This@AllArguments@Origin@SuperCall。你需要的越少,代理的效率就越高。特別是@AllArguments由於其分配要求而昂貴。

注意,在這種情況下,你的領域是隻有超級構造函數調用後設置。另外,你假定在超類型中有一個默認構造函數。或者,您可以實施自定義ConstructorStrategy

至於高速緩存,看看字節巴迪的TypeCache

+0

感謝提示w.r.t.緩存。我會使用'WeakHashMap ,類> else。 – lschuetze

+1

這不會工作,因爲該值是密鑰的子類並強烈引用它。而是使用'TypeCache'來解決這個問題,方法是輕微或弱地引用該值。 –

+0

它仍然是我不清楚我怎麼可能在'.intercept訪問新的'_core'參數(InvocationHandlerAdapter.of((代理,方法,m_args) - > proxyHandler(核心,方法,m_args);' – lschuetze