2015-11-07 51 views
0

代碼位於Scala中,但希望Java程序員也能理解。CGLIB的類生成和增強功能

我有以下類:

class SampleClass { 
    def test(in: String) = "Hello world!" 
} 

我有以下代碼創建這個類的一個增強的實例:

val e = new Enhancer 
e.setSuperclass(classOf[SampleClass]) 
e.setCallback(new Cb) 
println(e.create.asInstanceOf[SampleClass].test("foo")) 

回調函數如下:

class Cb extends MethodInterceptor { 
    override def intercept(obj: Any, m: Method, args: Array[Object], proxy: MethodProxy): Object = { 
    println(s"$m is called: ${m.getName}") 
    proxy.invokeSuper(obj, args) 
    } 
} 

這工作正常。現在,如果我不是嘗試創建一個類,然後它的一個新的實例,所有的方法都直接調用,繞過回調:

val e = new Enhancer 
e.setSuperclass(classOf[SampleClass]) 
e.setCallbackType(classOf[Cb]) 
println(e.createClass.newInstance.asInstanceOf[SampleClass].test("foo")) 

爲什麼會這樣?如何創建java.lang.Class並使用其newInstance()方法生成增強對象?

回答

0

解決了它。您需要實例化該實例,但避免在進程中調用其構造函數。然後你通過調用它的私有方法進行手工綁定的回調:

val instance = instantiator.newInstance.asInstanceOf[SampleClass] 

val bc = subclass.getDeclaredMethod("CGLIB$BIND_CALLBACKS", classOf[Object]) 
val stc = subclass.getDeclaredMethod("CGLIB$SET_THREAD_CALLBACKS", classOf[Array[Callback]]) 
bc .setAccessible(true) 
stc.setAccessible(true) 

stc.invoke(null, Array[Callback](new Cb)) 
bc .invoke(null, instance) 
stc.invoke(null, null) 

instantiator這裏是ObjectInstantiator類型 - 使用Objenesis避免調用構造函數。 subclass這裏是由e.createClass生成的子類。

避免在進程中調用構造函數很重要,因爲增強型構造函數將設置實例創建的標誌,並且不可能綁定回調。順便說一句,你應該在整個操作之後設置這個標誌,以保持一致性。它的名字是CGLIB$CONSTRUCTED

您可以看到增強構造函數如何工作here