发布日期:2019-08-12 17:39:21

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://github.com/cglib/cglib/blob/master/cglib-sample/src/main/java/net/sf/cglib/samples/Beans.java

https://www.cnblogs.com/jqyp/archive/2010/08/20/1805041.html

https://blog.csdn.net/zghwaicsdn/article/details/50957474

发表评论