Class 使用 CGLIB 生成和增强
Class generation and enhancement with CGLIB
代码是用 Scala 编写的,但希望 Java 程序员也能理解。
我有以下 class:
class SampleClass {
def test(in: String) = "Hello world!"
}
我有以下代码创建此 class 的增强实例:
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)
}
}
这很好用。现在,如果我尝试创建一个 class 然后创建它的一个新实例,所有方法都会被直接调用,绕过回调:
val e = new Enhancer
e.setSuperclass(classOf[SampleClass])
e.setCallbackType(classOf[Cb])
println(e.createClass.newInstance.asInstanceOf[SampleClass].test("foo"))
为什么会这样?如何创建 java.lang.Class
并使用其 newInstance()
方法生成增强对象?
解决了。您需要实例化实例,但避免在进程中调用其构造函数。然后通过调用其私有方法手动绑定回调:
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 - use Objenesis类型,避免调用构造函数。 subclass
这里是e.createClass
生成的子类。
避免在进程中调用构造函数很重要,因为增强的构造函数将设置实例已创建的标志,并且无法绑定回调。顺便说一句,为了保持一致性,您还应该在整个操作之后设置此标志。它的名字是 CGLIB$CONSTRUCTED.
您可以看到增强构造函数的工作原理here。
代码是用 Scala 编写的,但希望 Java 程序员也能理解。
我有以下 class:
class SampleClass {
def test(in: String) = "Hello world!"
}
我有以下代码创建此 class 的增强实例:
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)
}
}
这很好用。现在,如果我尝试创建一个 class 然后创建它的一个新实例,所有方法都会被直接调用,绕过回调:
val e = new Enhancer
e.setSuperclass(classOf[SampleClass])
e.setCallbackType(classOf[Cb])
println(e.createClass.newInstance.asInstanceOf[SampleClass].test("foo"))
为什么会这样?如何创建 java.lang.Class
并使用其 newInstance()
方法生成增强对象?
解决了。您需要实例化实例,但避免在进程中调用其构造函数。然后通过调用其私有方法手动绑定回调:
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 - use Objenesis类型,避免调用构造函数。 subclass
这里是e.createClass
生成的子类。
避免在进程中调用构造函数很重要,因为增强的构造函数将设置实例已创建的标志,并且无法绑定回调。顺便说一句,为了保持一致性,您还应该在整个操作之后设置此标志。它的名字是 CGLIB$CONSTRUCTED.
您可以看到增强构造函数的工作原理here。