代理模式

2020-04-23  本文已影响0人  jianshujoker

定义

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

静态代理

静态代理.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
/**
 * 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代理所真正执行的类

jdk生成类文件夹位置.png
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());
        }
    }
}

CGLIB

/**
 * cglib代理主题
 */
public class CglibSubject {
    public void doSomething(String sport) {
        System.out.println("do " + sport);
    }
}
/**
 * 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

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

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);
        }
    }
    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;
                ......
  }

JDK代理与CGLIB代理比较

代理、装饰、适配比较

优缺点

上一篇下一篇

猜你喜欢

热点阅读