【设计模式】(十一)--结构型模式--代理模式

【设计模式】(十一)–结构型模式–代理模式

代理模式定义

Provide a surrogate or placeholder for another object to control access to it.

意思就是:为其他对象提供一种代理一控制对这个对象的访问。
代理模式(Proxy Pattern)也称委托模式,在Java世界中经常遇见。后面接触的状态模式、策略模式、访问者模式本质上也是代理模式,只是表现形式突出重点不大一样而已。
代理模式一般有三个角色:

  1. 抽象 代理类与被代理类需要共同实现的接口。
  2. 代理类 也叫作委托类。持有被代理类的引用,在真是代理类方法执行的前后可以插入需要增强的内容。
  3. 被代理类 也叫被委托类,具体执行时会执行相关方法。

代理模式优点

  • 职责清晰。 被代理类只需要关注自身业务,对于多个同种类型的被代理类的共同业务能够抽取至代理类中统一处理。
  • 高扩展性。 只要实现抽象,代理类持有新的被代理类,那么就可以完成实际功能
  • 智能化。

代理模式的使用场景

按职责来划分,通常有以下使用场景:

  • 1、远程代理。
  • 2、虚拟代理。
  • 3、Copy-on-Write 代理。
  • 4、保护(Protect or Access)代理。
  • 5、Cache代理。
  • 6、防火墙(Firewall)代理。
  • 7、同步化(Synchronization)代理。
  • 8、智能引用(Smart Reference)代理。
    最常见的代理:远程代理、虚拟代理、智能引用代理、保护代理

简单的实现

类图
在这里插入图片描述

实现

public class Test {
    public static void main(String[] args) {
        GasCooker gasCooker = new GasCooker();
        Cooker cooker = new CookerProxy(gasCooker);
        cooker.start();
        cooker.stop();
    }
}
public interface Cooker {
    void start();

    void stop();
}
public class GasCooker implements Cooker {
    @Override
    public void start() {
        System.out.println("煤气灶点火成功!!大少开始煮饭炒菜吧!");
    }

    @Override
    public void stop() {
        System.out.println("炒菜结束,关火!");
    }
}
public class CookerProxy implements Cooker {

    private Cooker cooker;

    @Override
    public void start() {
        System.out.println("开始使用厨灶,开启煤气");
        cooker.start();
    }

    @Override
    public void stop() {
        cooker.stop();
        System.out.println("厨灶使用结束,关闭煤气");
    }

    public CookerProxy(Cooker cooker) {
        this.cooker = cooker;
    }
}

结果
在这里插入图片描述

静态代理

接上简单的代理实现,也称为静态代理,因为程序运行前代理类的字节码文件已经存在,代理类与被代理类的关系已经确定。

动态代理

动态代理类的源码是在程序运行期间由JVM根据反射等机制动态的生成,所以不存在代理类的字节码文件。代理类和委托类的关系是在程序运行时确定。

Java动态代理的常用实现

JDK原生动态代理

动态代理类和被代理类必须实现同一个接口。动态代理只能对接口中声明的方法进行代理。
原生动态代理有两个重要类

  • Proxy java.lang.reflect.Proxy是所有动态代理的父类。它通过静态方法newProxyInstance()来创建动态代理的class对象和实例。
  • InvocationHandler 每一个动态代理实例都有一个关联的InvocationHandler。通过代理实例调用方法,方法调用请求会被转发给InvocationHandler的invoke方法

JDK原生动态代理实现

GasCooker依旧使用静态代理的类

public class Test {
    public static void main(String[] args) {
        Cooker gasCooker = new GasCooker();
        CookerStartHandler cookerStartHandler = new CookerStartHandler();
        CookerStopHandler cookerStopHandler = new CookerStopHandler();
        Cooker cookerStartProxy = (Cooker) cookerStartHandler.getProxy(gasCooker);
        cookerStartProxy.start();
        Cooker cookerStopProxy = (Cooker) cookerStopHandler.getProxy(gasCooker);
        cookerStopProxy.stop();
    }
}

class CookerStartHandler implements InvocationHandler {
    Object obj;

    public Object getProxy(Object obj) {
        this.obj = obj;
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        doBefore();
        Object result = method.invoke(obj, args);
        doAfter();
        return result;
    }

    private void doBefore() {
        System.out.println("JDK动态代理--开始使用厨灶,开启煤气");
    }

    private void doAfter() {
        System.out.println("JDK动态代理--开启了,就维持火力");
    }
}

class CookerStopHandler implements InvocationHandler {
    Object obj;

    public Object getProxy(Object obj) {
        this.obj = obj;
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        doBefore();
        Object result = method.invoke(obj, args);
        doAfter();
        return result;
    }

    private void doBefore() {
        System.out.println("JDK动态代理--要关火了,等着关煤气");
    }

    private void doAfter() {
        System.out.println("JDK动态代理--厨灶使用结束,关闭煤气");
    }
}

结果
在这里插入图片描述

CGLib动态代理

CGLib(Code Generation Library)是一个基于ASM的字节码生成库。它允许我们在运行时对字节码进行修改或动态生成。CGLib通过继承被代理类的方式实现代理。
CGLib动态代理有两个重要类

  • Enhancer Enhancer指定要代理的目标对象。通过create方法得到代理对象。通过代理实例调用非final方法,方法调用请求会首先转发给MethodInterceptor的intercept
  • MethodInterceptor 通过代理实例调用方法,调用请求都会转发给intercept方法进行增强。

CGLib动态代理实现

maven 依赖

<!-- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.3.0</version>
</dependency>

public class Test {
    public static void main(String[] args) {
        Cooker cooker = new GasCooker();
        CookerStartInterceptor startInterceptor = new CookerStartInterceptor();
        CookerStopInterceptor stopInterceptor = new CookerStopInterceptor();
        Cooker startProxy = (Cooker) startInterceptor.getProxy(cooker);
        Cooker stopProxy = (Cooker) stopInterceptor.getProxy(cooker);
        startProxy.start();
        stopProxy.stop();
    }
}

class CookerStartInterceptor implements MethodInterceptor {
    Object target;

    public Object getProxy(Object target) {
        this.target = target;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(this.target.getClass());
        // 回调方法
        enhancer.setCallback(this);
        // 创建代理对象
        return enhancer.create();
    }

    private void doBefore() {
        System.out.println("CGLib动态代理--开始使用厨灶,开启煤气");
    }

    private void doAfter() {
        System.out.println("CGLib动态代理--开启了,就维持火力");
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        doBefore();
        Object result = methodProxy.invoke(target, objects);
        doAfter();
        return result;
    }
}

class CookerStopInterceptor implements MethodInterceptor {
    Object target;

    public Object getProxy(Object target) {
        this.target = target;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(this.target.getClass());
        // 回调方法
        enhancer.setCallback(this);
        // 创建代理对象
        return enhancer.create();
    }

    private void doBefore() {
        System.out.println("CGLib动态代理--要关火了,等着关煤气");
    }

    private void doAfter() {
        System.out.println("CGLib动态代理--厨灶使用结束,关闭煤气");
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        doBefore();
        Object result = methodProxy.invoke(target, objects);
        doAfter();
        return result;
    }
}

结果
在这里插入图片描述

原创文章 29 获赞 41 访问量 946

猜你喜欢

转载自blog.csdn.net/lovesunren/article/details/105827286