JDK代理要求被代理的类必须实现接口,有很强的局限性。而CGLIB动态代理则没有此类强制性要求。简单的说,CGLIB会让生成的代理类继承被代理类,并在代理类中对代理方法进行强化处理(前置处理、后置处理等)。在CGLIB底层,其实是借助了ASM这个非常强大的Java字节码生成框架。
使用CGLib实现动态代理,完全不受代理类必须实现接口的限制,而且CGLib底层采用ASM字节码生成框架,使用字节码技术生成代理类,比使用Java反射效率要高。唯一需要注意的是,CGLib不能对声明为final的方法进行代理,因为CGLib原理是动态生成被代理类的子类。
两者都动态生成了Proxy的java 类的字节码。
代理(Proxy) 从技术上来说可以分为静态代理和动态代理。 从业务上来说主要有两个业务对象,被代理的对象(Target Object)和代理本身(Proxy Object). 分别有两个Class文件. (Target Class) 和(Proxy Class). 静态代理中的Proxy Class就是预先写好的。而动态代理中的Proxy Class是动态生成的字节码。
静态代理的例子
public interface InterfaceA {
public void behavior();
}
public class AImpl implements InterfaceA {
@Override
public void behavior() {
System.out.println("This is AImpl's behavior method.");
}
}
public class AImpStaticProxy implements InterfaceA{
private AImpl aImpl;
public AImpStaticProxy(AImpl aImplObj){
this.aImpl = aImplObj;
}
@Override
public void behavior() {
System.out.println("Before calling the Target Object's method");
this.aImpl.behavior();
System.out.println("After calling the Target Object's method");
}
}
这里这个静态代理就代理了AImpl这个对象的behavior.
下面是动态代理
public class DynamicProxy implements InvocationHandler {
private Object targetObj;
public static Object newInstance(Object target){
return java.lang.reflect.Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new DynamicProxy(target));
}
private DynamicProxy(Object target){
this.targetObj = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result;
try {
System.out.println("In Dynamic Proxy: before method " + method.getName());
result = method.invoke(this.targetObj, args);
} catch (InvocationTargetException e) {
throw e.getTargetException();
} catch (Exception e) {
throw new RuntimeException("unexpected invocation exception: " +
e.getMessage());
} finally {
System.out.println("In Dynamic Proxy: after method " + method.getName());
}
return result;
}
}
用这个代理测试
public interface InterfaceB {
public void behavior();
}
public class BImpl implements InterfaceB {
@Override
public void behavior() {
System.out.println("This is BImpl");
}
}
public class Main {
public static void testDynamicPorxy(){
AImpl a = new AImpl();
InterfaceA aStaticProxy = new AImpStaticProxy(a);
aStaticProxy.behavior();
InterfaceA aDynamicProxy = (InterfaceA) DynamicProxy.newInstance(a);
aDynamicProxy.behavior();
InterfaceB b = new BImpl();
InterfaceB bDynamicProxy = (InterfaceB) DynamicProxy.newInstance(b);
bDynamicProxy.behavior();
}
public static void main(String[] args) throws Exception{
testDynamicPorxy();
}
}
输出:
Before calling the Target Object's method
This is AImpl's behavior method.
After calling the Target Object's method
In Dynamic Proxy: before method behavior
This is AImpl's behavior method.
In Dynamic Proxy: after method behavior
In Dynamic Proxy: before method behavior
This is BImpl
In Dynamic Proxy: after method behavior
上面这段例子中,动态生成了两个Proxy class。一个根据InterfaceA以及AImpl生成,一个根据InterfaceB及BImpl生成。这个动态生成的过程由下面的代码实现
java.lang.reflect.Proxy.newProxyInstance()
而最大可以生成65535个动态代理,如底层实现代码如下:
/**
* 生成一个代理类,但是在调用本方法之前必须进行权限检查
*/
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
//如果接口数量大于65535,抛出非法参数错误
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
// 如果在缓存中有对应的代理类,那么直接返回
// 否则代理类将有 ProxyClassFactory 来创建
return proxyClassCache.get(loader, interfaces);
}
Java的动态代理是基于接口的,所以可以CAST到接口上去,但是不能CAST到实现类上去,因为根本不是该实现类。
InterfaceA aDynamicProxy = (InterfaceA) DynamicProxy.newInstance(a);
aDynamicProxy.behavior();
InterfaceB b = new BImpl();
InterfaceB bDynamicProxy = (InterfaceB) DynamicProxy.newInstance(b);
bDynamicProxy.behavior();

动态生成的代理类名格式大体如下:$Proxy0, $Proxy1......
在我们这个例子中生成的代理类都有一个InvocationHandler成员变量,我们的例子中这个InvocationHandler就是我们定义的DynamicProxy.
换种写法,只实现InvocationHandler, 然后使用Proxy.newInstance来生成代理类和实例。
public class MyInvocationHandler implements InvocationHandler {
private Object targetObj;
public MyInvocationHandler(Object targetObj) {
this.targetObj = targetObj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result;
try {
beforeCall(proxy,method,args);
result = method.invoke(this.targetObj, args);
} catch (InvocationTargetException e) {
beforeException(proxy,method,args,e);
throw e.getTargetException();
} catch (Exception e) {
beforeException(proxy,method,args,e);
throw new RuntimeException("unexpected invocation exception: " +
e.getMessage());
} finally {
afterCall(proxy,method,args);
}
return result;
}
public void beforeCall(Object proxy, Method method, Object[] args) {
System.out.println("In MyInvokeHandler Proxy: before method " + method.getName());
}
public void afterCall(Object proxy, Method method, Object[] args) {
System.out.println("In MyInvokeHandler Proxy: " + method.getName());
}
public void beforeException(Object proxy, Method method, Object[] args,Exception e){
System.out.println("In MyInvokeHandler Proxy:" + e.getMessage());
}
}
public class Main {
public static void testDynamicPorxy(){
AImpl a = new AImpl();
InterfaceA aStaticProxy = new AImpStaticProxy(a);
aStaticProxy.behavior();
InterfaceA aDynamicProxy = (InterfaceA) DynamicProxy.newInstance(a);
aDynamicProxy.behavior();
InterfaceB b = new BImpl();
InterfaceB bDynamicProxy = (InterfaceB) DynamicProxy.newInstance(b);
bDynamicProxy.behavior();
System.out.println("===========InvocationHandler===========");
InterfaceA a1Proxy = (InterfaceA)Proxy.newProxyInstance(a.getClass().getClassLoader(),a.getClass().getInterfaces(),new MyInvocationHandler(a));
a1Proxy.behavior();
}
public static void main(String[] args) throws Exception{
testDynamicPorxy();
}
}

参考文档:
https://docs.oracle.com/javase/8/docs/technotes/guides/reflection/proxy.html
https://github.com/cglib/cglib
https://www.cnblogs.com/jqyp/archive/2010/08/20/1805041.html