代理模式(Proxy Pattern)

2020-12-21  本文已影响0人  慕尼黑凌晨四点

简介

代理,原本要自己做的事情,拿去给别人做了。比如说A类的invokeA()方法中调用B.invokeB()方法。

防止直接访问目标对象给系统带来的不必要复杂性。

image-20201221100808172.png

静态代理

上面这种类图是静态代理,不看代码了。

动态代理

先随便写一个需要代理的类;

interface Hero { void Q(); }
public class YaSuo implements Hero{
    @Override
    public void Q() {
        System.out.println("hasak");
    }
}

JDK动态代理

需要用到Java反射机制。用java.lang.reflect.Proxy进行动态代理:

YaSuo yaSuo = new YaSuo();
Hero proxyYs = (Hero) Proxy.newProxyInstance(yaSuo.getClass().getClassLoader(),yaSuo.getClass().getInterfaces(), new InvocationHandler() {
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //do something before
        return method.invoke(yaSuo);
        //do sonmething after
    }
});
proxyYs.Q();

生成的proxyYs就是我们想要的代理类了,它继承了原被代理类的所有接口 外加一个Proxy类,实现接口所有方法,并在内部代理给原对象。

想看生成的代理类 代码 ,可以在VM -options中添加:-Dsun.misc.ProxyGenerator.saveGeneratedFiles=true 。生成的类文件如下:

final class $Proxy0 extends Proxy implements Hero {
    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 Q() 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("proxy.Hero").getMethod("Q");
            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动态代理

基于ASM机制实现,通过生成业务类的子类作为代理类。需要引入cglib。

<dependency>
  <groupId>cglib</groupId>
  <artifactId>cglib</artifactId>
  <version>3.3.0</version>
</dependency>
implementation 'cglib:cglib:3.3.0'

使用:

Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(YaSuo.class);
enhancer.setCallback(new MethodInterceptor(){
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        methodProxy.invokeSuper(o,objects);
        return objects;
    }
});

YaSuo proxy = (YaSuo) enhancer.create();
proxy.Q();

JDK Proxy 的优势:

基于类似 cglib 框架的优势:


以下部分来自于:作者:小旋锋
链接:https://juejin.cn/post/6844903744954433544
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

面试题

描述动态代理的几种实现方式?分别说出相应的优缺点

代理可以分为 "静态代理" 和 "动态代理",动态代理又分为 "JDK动态代理" 和 "CGLIB动态代理" 实现。

静态代理:代理对象和实际对象都继承了同一个接口,在代理对象中指向的是实际对象的实例,这样对外暴露的是代理对象而真正调用的是 Real Object

JDK 动态代理

CGLIB 代理

上一篇 下一篇

猜你喜欢

热点阅读