美文网首页
代理模式

代理模式

作者: jianshujoker | 来源:发表于2020-04-23 00:47 被阅读0次

    定义

    为其他对象提供一种代理,以控制对对象的访问,结构型模式。某些情况下,一个对象不适合或者不能直接引用对象,而代理对象可以在客户端和目标对象之间起到个中介的作用。

    • 作用:一是保护目标对象,二是增强目标对象;而我们在代码里一般都是为了增强目标对象,像spring中的aop。

    静态代理

    静态代理.png
    • 代理主题
    /**
     * 主题
     */
    public interface Subject {
        void doSomething();
    }
    
    • 真实执行角色
    /**
     * 真正的执行主题
     */
    public class RealSubject implements Subject{
    
        @Override
        public void doSomething() {
            System.out.println("RealSubject doSomething");
        }
    }
    
    • 静态代理类
    /**
     * 静态代理类
     */
    public class StaticProxy implements Subject{
        private RealSubject realSubject;
    
        private StaticProxy(RealSubject realSubject) {
            this.realSubject = realSubject;
        }
    
        @Override
        public void doSomething() {
            System.out.println("proxy doSomething1");
            realSubject.doSomething();
            System.out.println("proxy doSomething2");
        }
    }
    

    动态代理

    JDK

    JDK动态代理.png
    • JdkProxy
    /**
     * jdk动态代理,通过代理对象的接口生成代理方法,即被代理者
     * 必须有实现的接口
     */
    public class JdkProxy implements InvocationHandler {
    
        Object subject;
    
        public Object newProxyInstance(Object subject) {
            this.subject = subject;
            Class<?> classSbject = subject.getClass();
            return Proxy.newProxyInstance(classSbject.getClassLoader(), classSbject.getInterfaces(), this);
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            before();
            Object result = method.invoke(subject, args);
            after();
            return result;
        }
    
        private void before() {
            System.out.println("before doSomething");
        }
    
        private void after() {
            System.out.println("after doSomething");
        }
    }
    
    • 调用客户端
    /**
     * 调用jdk动态代理的客户端
     */
    public class Client {
        public static void main(String[] args) {
            JdkProxy jdkProxy = new JdkProxy();
            Subject subjectProxyInstance = (Subject) jdkProxy.newProxyInstance(new RealSubject());
            subjectProxyInstance.doSomething();
        }
    }
    

    JDK代理所真正执行的类

    • 让我们把断点打在ProxyGenerator.generateProxyClass方法里,并通过System.getProperties().put设置saveGeneratedFiles这个变量为true,我们就可以看到真实生成的代理类是怎么样的了


      jdk生成类位置.png
    jdk生成类文件夹位置.png
    • jdk代理生成的代理类
    public final class $Proxy0 extends Proxy implements Subject {
        private static Method m1;
        private static Method m3;
        private static Method m2;
        private static Method m0;
    
        public $Proxy0(InvocationHandler var1) throws  {
            super(var1);
        }
    
        public final boolean equals(Object var1) throws  {
            try {
                return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
            } catch (RuntimeException | Error var3) {
                throw var3;
            } catch (Throwable var4) {
                throw new UndeclaredThrowableException(var4);
            }
        }
    
        public final void doSomething() throws  {
            try {
                super.h.invoke(this, m3, (Object[])null);
            } catch (RuntimeException | Error var2) {
                throw var2;
            } catch (Throwable var3) {
                throw new UndeclaredThrowableException(var3);
            }
        }
    
        public final String toString() throws  {
            try {
                return (String)super.h.invoke(this, m2, (Object[])null);
            } catch (RuntimeException | Error var2) {
                throw var2;
            } catch (Throwable var3) {
                throw new UndeclaredThrowableException(var3);
            }
        }
    
        public final int hashCode() throws  {
            try {
                return (Integer)super.h.invoke(this, m0, (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"));
                m3 = Class.forName("com.example.proxy.dynamicproxy.jdkproxy.Subject").getMethod("doSomething");
                m2 = Class.forName("java.lang.Object").getMethod("toString");
                m0 = Class.forName("java.lang.Object").getMethod("hashCode");
            } catch (NoSuchMethodException var2) {
                throw new NoSuchMethodError(var2.getMessage());
            } catch (ClassNotFoundException var3) {
                throw new NoClassDefFoundError(var3.getMessage());
            }
        }
    }
    
    • 对比前面的JdkProxy,我们可以发现,真正执行的方法就是JdkProxy里面的invoke方法

    CGLIB

    • cglib代理主题
    /**
     * cglib代理主题
     */
    public class CglibSubject {
        public void doSomething(String sport) {
            System.out.println("do " + sport);
        }
    }
    
    • cglib动态代理
    /**
     * cglib动态代理
     */
    public class CglibProxy implements MethodInterceptor {
        public Object getProxyInstance(Class<?> clazz) {
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(clazz);
            enhancer.setCallback(this);
            return enhancer.create();
        }
    
        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            before();
            Object result = methodProxy.invokeSuper(o, objects);
            after();
            return result;
        }
    
        private void before() {
            System.out.println("cglib before doSomething");
        }
    
        public void after() {
            System.out.println("cglib after doSomething");
        }
    }
    
    • 客户端
    public class Client {
        public static void main(String[] args) {
            System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D://cglib_proxy_classes");
            CglibSubject cglibSubjectProxy = (CglibSubject) new CglibProxy().getProxyInstance(CglibSubject.class);
            cglibSubjectProxy.doSomething("basketball");
        }
    }
    

    通过设置DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,我们可以看到cglib生成的代理类


    cglib1.png

    我们看这三个类中比较重要的方法

    • CglibSubjectEnhancerByCGLIB328a458c.class
    public final void doSomething(String var1) {
            // 即继承了MethodInterceptor的CglibProxy
            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$doSomething$0$Method, new Object[]{var1}, CGLIB$doSomething$0$Proxy);
            } else {
                super.doSomething(var1);
            }
        }
    
    • CglibSubjectFastClassByCGLIBf11f64a9
        public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
            //真实被代理的对象
            CglibSubject var10000 = (CglibSubject)var2;
            int var10001 = var1;
    
            try {
                switch(var10001) {
                case 0:
                    // 根据索引选择真实执行的方法,而不是反射
                    var10000.doSomething((String)var3[0]);
                    return null;
                    ......
      }
    
    • CglibSubjectEnhancerByCGLIB328a458cFastClassByCGLIB8d4d8eb1
      • 和CglibSubjectFastClassByCGLIBf11f64a9一样主要是通过下标执行方法

    JDK代理与CGLIB代理比较

    • JDK生成代理是靠接口,CGLIB是覆盖方法
    • JDK的无法生成extend的方法,CGLIB无法覆盖final的方法
    • JDK是靠反射,CGLIB是靠下标找到执行方法,CGLIB这点比JDK高效

    代理、装饰、适配比较

    • 这三个设计模式从使用上来说比较相像,都是持有一个对象,再在调用持有对象方法时做些额外的事。它们的区别主要在于意图,代理是增强,装饰是扩展,适配是转换。

    优缺点

    • 优点
      • 解耦
      • 保护目标
      • 增强功能
    • 缺点
      • 增加类的数量
      • 增加复杂度

    相关文章

      网友评论

          本文标题:代理模式

          本文链接:https://www.haomeiwen.com/subject/ngenihtx.html