【图解设计模式系列】The Proxy Pattern: 代理模式

定义:
代理模式给某一个对象提供了一个代理对象,并由代理对象控制对原对象的引用。在一些情况下,一个客户端不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之间起到中介作用。

Proxy Pattern
provides a surrogate or placeholder for another object to control access to it.
Use the proxy pattern to create a representative object that controls access to another object, which may be remote, expensive to create or in need of securing.
few ways proxies control access:

  • a remote proxy controls access to a remote object
  • a virtual proxy controls access to a resource that is expensive to
    create
  • a protection proxy controls access to a resource based on access
    rights

【图解设计模式系列】The Proxy Pattern: 代理模式_第1张图片
代理模式中的角色:

●抽象对象角色:声明了目标对象和代理对象的共同接口,这样一来在任何可以使用目标对象的地方都可以使用代理对象。

●目标对象角色:定义了代理对象所代表的目标对象。

●代理对象角色:代理对象内部含有目标对象的引用,从而可以在任何时候操作目标对象;代理对象提供一个与目标对象相同的接口,以便可以在任何时候替代目标对象。代理对象通常在客户端调用传递给目标对象之前或之后执行某个操作,而不是单纯地将调用传递给目标对象。

静态代理和动态代理

上面的例子实际上是静态代理,静态代理指在编译期就生成了代理对象。显然ProxySubject类是由我们手动实现的,最终会被编译成class文件,这是编译期间完成的,所以就是静态代理。相反,动态代理指的就是在运行时生成代理对象,也就是代理类不是我们在编码时就把该类实现了,而是由程序动态生成,程序运行时自然属于运行期,所以就是动态代理。

静态代理和动态代理的区别可以理解为一个被事先植入流氓程序的app在运行过程中弹广告,和一个正常app在运行过程中被流氓程序拦截而弹出广告。一个是事先增强,一个是运行时动态增强。
【图解设计模式系列】The Proxy Pattern: 代理模式_第2张图片

四、动态代理的几种实现
动态代理的实现方式主要有:JDK动态代理、ASM底层实现和CGLIB与javassist等高级实现。

1.JDK动态代理
其实JDK中已经提供了对动态代理内置的支持,Proxy官方文档

JDK动态代理只需要用到3个类:

  • Proxy
  • CLassLoader
  • InvocationHandler
public class Client {
     

    public static void main(String[] args) {
     
        // 真实角色
        Subject realSubject = new RealSubject();

        ClassLoader loader = RealSubject.class.getClassLoader();// 与真实角色具有相同的classloader
        Class<?>[] interfaces = {
      Subject.class };// 共同的接口
        InvocationHandler h = new MyInvocationHandler(realSubject);// 实现增强操作
        // 代理角色(动态创建)
        Subject proxy = (Subject) Proxy.newProxyInstance(loader, interfaces, h);

        // 真实角色的操作
        realSubject.request();
        // 代理角色代替真实角色进行操作
        proxy.request();
    }

}

class MyInvocationHandler implements InvocationHandler {
     
    private Subject realSubject;

    public MyInvocationHandler(Subject realSubject) {
     
        this.realSubject = realSubject;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
     
        // 前置增强
        preRequest();
        Object rs = method.invoke(realSubject, args);
        // 后置增强
        postRequest();
        return rs;
    }

    private void preRequest() {
     
        System.out.println("增强操作:before操作");
    }

    private void postRequest() {
     
        System.out.println("增强操作:after操作");
    }

}

…其他还有很多 如果想进一步了解 请参见https://www.cnblogs.com/rouqinglangzi/p/7010536.html

代理模式和装饰者模式的区别

代理模式和装饰者模式确实挺像的,但是他们的区别是关注点或者说意图不同。

装饰者模式的意图是对对象进行功能上的增强。

代理模式的意图是给对象提供一个代理对象,让代理对象来控制对原对象的访问。

总结

总结

1.代理的作用

代理模式给某一个对象提供了一个代理对象,并由代理对象控制对原对象的引用

2.静态代理和动态代理的区别

3.动态代理的实现方式

JDK动态代理、asm/cglib、javassist

1.实现原理区别

JDK动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。

CGLIB使用底层字节码技术(asm开源库),把目标类的class文件加载进来,为目标类创建一个子类,并在父类方法中采用方法拦截的技术拦截对父类方法的调用,并顺势织入横切逻辑。

2.各自缺陷

JDK动态代理只能对实现了接口的类进行代理。

CGLIB不能对final类和final方法生成动态代理类。

最后要搞清楚的问题:

1.为什么JDK动态代理只能对实现类了接口的类进行代理,而不能对继承了其它类的类进行代理?

2.通过实验可以发现JDK动态代理生成的代理类会继承自Proxy类,为什么非要继承Proxy类呢?

3.既然CGLIB没有JDK的局限性,为什么就没有取代JDK动态代理?例如Spring AOP的实现中就两者并存。

你可能感兴趣的:(Design,Pattern)