• 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源码解读

    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出。
  • 相关阅读:
    React组件二
    React组件一
    React新接触
    清除浮动的方法
    div section article aside的理解
    html引入外部的jswenjian
    绘制扇形,空心文字,实心文字,颜色线性 放射性渐变
    绘制扇形空心 实心文字 ,颜色线性渐变,颜色放射性渐变
    绘制圆弧的几种简单方法
    求两个有序数组的中位数
  • 原文地址:https://www.cnblogs.com/caozibiao/p/13974891.html
Copyright © 2020-2023  润新知