Cglib的几种Callback简介

Callback是Cglib中一个比较核心的概念,看一下下面的示例代码:

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class Test {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(Person.class);
        enhancer.setCallback(new MethodInterceptor() {
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                System.out.println("Intercept!");
                methodProxy.invokeSuper(o, objects);
                return null;
            }
        });
        Person person = (Person) enhancer.create();
        person.sayHello();
    }
}

其中,先给Enchancer类设置一个需要被代理的类Person,然后设置CallbackCallback可以理解成生成的代理类的方法被调用时(比如说调用person.sayHello()时),会执行的逻辑。

Callback是一个空的接口,在Cglib中它的实现类有以下几种:

  1. MethodInterceptor
  2. NoOp
  3. LazyLoader
  4. Dispatcher
  5. InvocationHandler
  6. FixedValue

下面分别来介绍一下。首先是MethodInterceptor,这是一个功能很强大的接口,它可以实现类似于AOP编程中的环绕增强(around-advice)。它只有一个方法public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args,
MethodProxy proxy) throws Throwable;
。代理类的所有方法调用都会转而执行这个接口中的intercept方法而不是原方法。如果需要在intercept方法中执行原方法可以使用参数method进行反射调用或者使用参数proxy,后者会快一些(反射调用比正常的方法调用的速度慢很多)。MethodInterceptor允许我们完全控制被拦截的方法,并且提供了手段对原方法进行调用,那为什么还会有其它的Callback接口实现呢?因为 MethodInterceptor的效率不高,它需要产生不同类型的字节码,并且需要生成一些运行时对象(InvocationHandler就不需要),所以Cglib提供了其它的接口供我们选择。

接下来是NoOp,就像它的名字一样,这个接口只是简单地把方法调用委托给了被代理类的原方法(本例中是Person),不做任何其它的操作。然后看一下LazyLoader,它也提供了一个方法:Object loadObject() throws Exception;loadObject()方法会在第一次被代理类的方法调用时触发,它返回一个代理类的对象,这个对象会被存储起来然后负责所有被代理类方法的调用,就像它的名字说的那样,一种lazy模式。如果被代理类或者代理类的对象的创建比较麻烦,而且不确定它是否会被使用,那么可以选择使用这种lazy模式来延迟生成代理。

然后是DispatcherDispatcherLazyLoader接口相同,也是提供了loadObject()方法,这个方法同样地返回一个代理对象,这个对象同样可以代理原方法的调用。不过它们之间不同的地方在于,DispatcherloadObject()方法在每次发生对原方法的调用时都会被调用并返回一个代理对象来调用原方法。也就是说DispatcherloadObject()方法返回的对象并不会被存储起来,可以类比成Spring中的Prototype类型,而LazyLoader则是lazy模式的Singleton

然后是InvocationHandler,它的使用方式和MethodInterceptor差不多:

```
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class Test {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(Person.class);
        enhancer.setCallback(new InvocationHandler() {
            public Object invoke(Object proxy, Method method, Object[] objects) throws Throwable {
                System.out.println("Intercept!");
                return null;
            }
        });
        Person person = (Person) enhancer.create();
        person.sayHello();
    }
}

需要注意的一点是,所有对invoke()方法的参数proxy对象的方法调用都会被委托给同一个InvocationHandler,所以可能会导致无限循环。

最后是FixedValue,它同样也提供了一个loadObject()方法,不过这个方法返回的不是代理对象,而是原方法调用想要的结果。也就是说,在这个Callback里面,看不到任何原方法的信息,也就没有调用原方法的逻辑,不管原方法是什么都只会调用loadObject()并返回一个结果。听起来可能有些没有,但是配合CllbackFilter可以强制使某个方法返回固定的值,并且带来的开销很小。需要注意的是,如果loadObject()方法的返回值并不能转换成原方法的返回值类型,那么会抛出类型转换异常。

  • 6
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值