Java SDK动态代理的局限性
我们知道如果要使用java sdk的动态代理,那么我们必须要创建一个代理的接口,并且返回的代理对象也只能转换到某个接口类型,但是如果遇到了一个类,它没有接口,我们还要代理他的功能,或者希望代理非接口中的方法的话,就不太好实现了。这时第三方库cglib就可以解决这个问题。
cglib动态代理
首先来看它的实例
public class SimpleCGLibDemo {
//表示被代理的类
static class RealService {
public void sayHello() {
System.out.println("hello");
}
}
static class SimpleInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object object, Method method,
Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("entering " + method.getName());
Object result = proxy.invokeSuper(object, args);
System.out.println("leaving " + method.getName());
return result;
}
}
@SuppressWarnings("unchecked")
//为被代理的类生成代理对象
private static <T> T getProxy(Class<T> cls) {
Enhancer enhancer = new Enhancer();
//设置被代理的类
enhancer.setSuperclass(cls);
//设置被代理类的public非final方法,被调用时的处理类
enhancer.setCallback(new SimpleInterceptor());
return (T) enhancer.create();
}
public static void main(String[] args) throws Exception {
RealService proxyService = getProxy(RealService.class);
proxyService.sayHello();
}
}
可以看出使用它的话,只要在代理类上实现MethodInterceptor接口就好了,然后重写intercept方法就好。实际上这里可以对彪java sdk中的InvocationHandler接口,在重写的intercept方法中多了一个MethodProxy proxy参数。
java sdk动态代理 | cglib动态代理 | |
---|---|---|
继承接口 | InvocationHandler | MethodInterceptor |
重写方法 | invoke | intercept |
重写方法参数 | Object proxy, Method method, Object[] args | Object object, Method method,Object[] args, MethodProxy proxy |
执行方法代码 | method.invoke(realObj,args); | proxy.invokeSuper(object, args); |
从以上的表格中可以看出这两种动态代理应用的具体区别,既然cglib不依赖于具体的接口,那么我们可以得知它是通过继承实现的
两者的比较
- java sdk代理
- java sdk代理面向的是一组接口
- 它为这些接口动态创建了一个实现类,并且可以在InvocationHandler中自定义接口的具体逻辑
- 实现是自定义的,其背后不一定有真正被代理的对象,也可能有多个实际对象(一个接口可以被多个类实现)
- 实际上代理的是对象,而不是一个具体的类
- 有一个实际对象,自定义的InvocationHandler引用该对象,在动态创建一个代理类,和代理对象,访问代理对象,代理对象在调用实际对象的方法
- cglib代理
- 代理的是一个具体的类,对象只有一个,基于继承实现
- 也会动态创建一个类,这个类的父类是被代理的类,并且重写了父类的所有public非final方法