jdk动态代理和cglib动态代理

https://blog.csdn.net/ywlmsm1224811/article/details/92583559
https://www.bilibili.com/video/BV1SJ411v7fq?p=2

静态代理

示例
public class StaticProxy {
    private Subject subject;
    public StaticProxy() {}

    public StaticProxy(Subject subject) {
        this.subject = subject;
    }

    public void request() {
        System.out.println("静态代理");
        subject.request();
    }
}
public class StaticProxyTest {
    public static void main(String[] args) {
        RealSubject realSubject = new RealSubject();
        StaticProxy staticProxy = new StaticProxy(realSubject);
        staticProxy.request();
    }
}
静态代理的缺点
  • 当目标类增加了,代理类可能也需要成倍的增加,代理类数量过多
  • 当接口更新(功能增加或修改),会影响众多实现类,各代理类也需要修改

jdk动态代理

jdk动态代理写法:
  1. 被代理接口及其实现类
  2. 实现InvocationHandler invoke方法,传入参数为代理对象和参数,在此方法中进行功能增强
  3. 测试类通过调用Proxy.newProxyInstance()生成proxy对象,传入对象分别为被代理类加载器、被代理类接口、和InvocationHandler的实现类实例化对象

被代理接口及其实现类

public interface Subject {
    void request();
}

public class RealSubject implements Subject {
    @Override
    public void request() {
        System.out.println("execute real subject!");
    }
}

InvocationHandler实现

public class MyInvocationHandler implements InvocationHandler {

    private Object target;

    public MyInvocationHandler(Object target) {
        this.target = target;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("-----before-----");
        method.invoke(target, args);
        System.out.println("-----after------");
        return null;
    }
}

测试

public class DynamicProxyTest {
    public static void main(String[] args) {
        MyInvocationHandler myInvocationHandler = new MyInvocationHandler(new RealSubject());
        Subject proxy = (Subject) Proxy.newProxyInstance(RealSubject.class.getClassLoader(),
                    RealSubject.class.getInterfaces(), myInvocationHandler);
        proxy.request();

    }
}
源码
生成Proxy代理类

添加以下属性,会自动在默认com.sun.proxy包下生成$Proxy0.class文件。主要通过Proxy中内部类ProxyClassFactory调用apply方法,从而调用ProxyGenerator中generateProxyClass生成。

System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");

此属性可在ProxyGenerator中查看,

private static final boolean saveGeneratedFiles = (Boolean)AccessController.doPrivileged(new GetBooleanAction("sun.misc.ProxyGenerator.saveGeneratedFiles"));
    
if (saveGeneratedFiles) {......}

生成的文件为:

package com.sun.proxy;

import com.java.study.spring.aop.Subject;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy0 extends Proxy implements Subject {
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m0;

    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }

    ......   

    public final void request() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("com.java.study.spring.aop.Subject").getMethod("request");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

所以proxy.request()是等同先执行$Proxy0.request(),super.h是之前传入InvocationHandler的实现类,调用invoke方法进行功能增加后,再通过发射,执行实际被代理类方法

是Proxy——>InvocationHandler-->Subject顺序

CGLIB

对类的代理
public class TargetProxy implements MethodInterceptor {

    public <T> T getProxy(Class clazz) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        return (T)enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("cglib proxy");
        return methodProxy.invokeSuper(o, objects);
    }
}
public class CglibTest {
    public static void main(String[] args) {
        TargetProxy targetProxy = new TargetProxy();
        RealSubject proxy = targetProxy.getProxy(RealSubject.class);
        proxy.request();
    }
}
对接口代理

如果是接口,需要在interceptor中进行实现

@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
    System.out.println("cglib 接口实现");
    return "接口实现";
}
CGLIB源码

加以下可将增强类输出

System.getProperties().put(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"/.../com/sun/proxy/");
public class RealSubject$$EnhancerByCGLIB$$e5ed5f82 extends RealSubject implements Factory {


    final void CGLIB$request$0() {
        super.request();
    }

    public final void request() {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        if (var10000 != null) {
            var10000.intercept(this, CGLIB$request$0$Method, CGLIB$emptyArgs, CGLIB$request$0$Proxy);
        } else {
            super.request();
        }
    }

    final boolean CGLIB$equals$1(Object var1) {
        return super.equals(var1);
    }
    
    ......
  
注意

由于是继承方式,所以final修饰的类和方法不可被增强

总结

JDK动态代理和CGLIB的区别:

  1. JDK动态代理:是通过反射机制生成一个实现代理接口的的类(在jvm内存中),核心是实现InvocationHandler接口,重写invoke方法进行面向切面的处理,调用相应通知

CGLIB动态代理:动态生成一个要代理类的子类,子类重写要代理类(非final修饰)的不是final的方法,在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑;比JDK动态代理要快

  1. JDK不能对接口进行代理,CGLIB不能对final修饰类和方法进行代理

在spring中:

  • 如果目标对象实现了接口,默认使用JDK动态代理;也可强制使用CGLIB
  • 如果目标对象没有实现接口,必须采用CGLIB动态代理

TODO

JDK源码解读
CGLIB源码解读

posted @ 2020-11-14 21:48  曹自标  阅读(100)  评论(0编辑  收藏  举报