代理模式

110 阅读2分钟

介绍

代理模式分为以下三种角色:

  • 抽象主题(Subject):真实主题和代理主题的共同接口。
  • 代理类: 通过对真实主题的引用,扩展真实主题。
  • 真实主题:实现抽象主题,在代理中被引用。

image.png

静态代理

public interface Subject {

    void req();
}
public class Proxy implements Subject {

    private Subject subject;

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

    @Override
    public void req() {
        System.out.println("Proxy req before----");
        subject.req();
        System.out.println("Proxy req after----");
    }
}
public class RealSubject implements Subject {
    @Override
    public void req() {
        System.out.println("RealSubject req");
    }
}
@Test
public void test() {
    Subject subject=new RealSubject();
    Subject subject1=new Proxy(subject);
    subject1.req();

}

Jdk动态代理

用Jdk的api,动态生成类的代理相比硬编码生成的代理方式更加的灵活。

public class HandlerDemo implements InvocationHandler {

    private Object target;

    public HandlerDemo(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        System.out.println("invoke method before----");

        Object result = method.invoke(target, args);

        System.out.println("invoke method after----");

        return result;
    }
}
@Test
public void test() {
    Subject demo = new RealSubject();
    HandlerDemo handlerDemo = new HandlerDemo(demo);
    Subject o = (Subject) Proxy.newProxyInstance(demo.getClass().getClassLoader(), demo.getClass().getInterfaces(), handlerDemo);
    o.req();

}

原理

类在被jvm加载的时候分为五个阶段,加载,验证,准备,解析,初始化。在加载的时候,第一步,通过类的全限定名获取类的二进制字节流,第二步,将类的静态结构加载到运行时数据区的方法区,第三步,生成java.lang.Class对象作为方法区访问这个类的入口。第一步获取类的二进制字节流的时候有很多种方式,比如从网络中获取,本地获取,运行的时候生成。Jdk动态代理就是通过运行时生成类的代理类,加载进jvm中使用的。

生成的代理类分析

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 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 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 void req() throws  {
        try {
            super.h.invoke(this, m3, (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"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("com.ex.proxy.Subject").getMethod("req");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

13行代码super.h.invoke(this, m1, new Object[]{var1})调用父类InvocationHandler invoke()方法执行的是HandlerDemo 类的invoke(),HandlerDemo 类的此行代码Object result = method.invoke(target, args)掉的是最终我们自己方法

cglib代理

Jdk的动态代理代理的是实现接口的类,没有实现接口的类可以用cglib代理。

public class CglibProxy implements MethodInterceptor {


    private Object target;

    public CglibProxy(Object target) {
        this.target = target;
    }

    public Object getInstance() {

        Enhancer en = new Enhancer();
        en.setSuperclass(target.getClass());
        en.setCallback(this);
        return en.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("cglib invoke method before----");

        Object result = methodProxy.invokeSuper(target, objects);

        System.out.println("cglib invoke method after----");
        return result;
    }
}
@Test
public void test() {
    ProxyDemo proxyDemo = new ProxyDemo();
    ProxyDemo instance = (ProxyDemo) new CglibProxy(proxyDemo).getInstance();
    instance.req();

}