【学习笔记】设计模式-代理模式(Proxy)

文章目录

  • 0 设计模式
  • 1 代理模式
  • 2 实现思路
    • 2.1 静态代理实现思路
    • 2.2 动态代理执行过程和实现思路
      • 2.2.1 JDK动态代理执行过程
      • 2.2.2 动态代理
  • 3 需要的类
    • 3.1 静态代理需要的类
    • 3.2 动态代理需要的类
  • 4 具体实现
    • 4.1 静态代理具体实现
      • 4.1.1 Movable接口
      • 4.1.2 Tank(被代理的实体类,实现Movable)
      • 4.1.3 代理类(实现Movable)
      • 4.1.4 测试类
    • 4.2 动态代理具体实现
      • 4.2.1 Movable接口
      • 4.2.2 Tank(实现Movable)
      • 4.2.3 LogHandler(代理类,实现InvocationHandler接口)
      • 4.2.4 测试类
  • 5 扩展(AOP)
    • 5.1 动态代理引入AOP的概念
    • 5.2 引入AOP思想后的代码
  • 6 思维导图
  • 7 示例源码地址
  • 最后

0 设计模式

不了解设计模式的小伙伴可以通过这篇文章了解一下什么是设计模式

https://blog.csdn.net/qq_42874315/article/details/120006447?spm=1001.2014.3001.5502

1 代理模式

代理模式和装饰器很像,都是给目标对象增加额外的方法,核心思想就是AOP,在不改变原有方法逻辑和代码的情况下,动态的给某个(某些)方法去添加功能,由此引出面向切面编程的思想。

从代理方式又可以分为静态代理动态代理

区别

​ 静态代理可以看到代码(自己写的代码)

​ 动态代理看不到代理的代码

2 实现思路

2.1 静态代理实现思路

【学习笔记】设计模式-代理模式(Proxy)_第1张图片

在主方法中面向代理去执行

2.2 动态代理执行过程和实现思路

2.2.1 JDK动态代理执行过程

【学习笔记】设计模式-代理模式(Proxy)_第2张图片

2.2.2 动态代理

【学习笔记】设计模式-代理模式(Proxy)_第3张图片

在主方法中面向Proxy.newProxyInstance()创建出的代理对象去执行

3 需要的类

3.1 静态代理需要的类

  1. 被代理的类抽象出的接口

  2. 被代理的类(实现接口)

  3. 代理类(实现接口)

    需要聚合代理接口,并且在构造的时候就赋值

    在代理类中,在构造的时候对聚合的接口进行赋值,这样可以实现链式代理(责任链的思想)

  4. 测试类

    面向代理去调用

3.2 动态代理需要的类

  1. 被代理的类抽象出的接口

  2. 被代理的类(实现接口)

  3. 代理类

    实现JDK自带的InvocationHandler接口,重写invoke方法

  4. 测试类

    使用Proxy.newProxyInstance()去创建代理对象

Proxy.newProxyInstance()方法说明

Proxy.newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler handler)

方法的返回值为被代理的对象

loader:指定用哪个Classloader来把将来返回来的代理对象漏到内存(跟被代理对象用同一个就好)

interfaces:代理对象应该实现哪些接口(被new出来的对象要实现这个接口)

handler:调用处理器,其实就是实现了InvocationHandler的代理类

4 具体实现

4.1 静态代理具体实现

4.1.1 Movable接口

/**
 * @Author ChenJiahao(程序员五条)
 * @Date 2021/9/16 23:23
 */
public interface Movable {
    void move();
}

4.1.2 Tank(被代理的实体类,实现Movable)

/**
 * @Author ChenJiahao(程序员五条)
 * @Date 2021/9/16 23:23
 */
public class Tank implements Movable{
    @Override
    public void move() {
        System.out.println("Tank moving claclacla....");
        try {
            // 随机睡眠10秒
            Thread.sleep(new Random().nextInt(10000));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

4.1.3 代理类(实现Movable)

TankLogProxy

/**
 * @Author ChenJiahao(程序员五条)
 * @Date 2021/9/16 23:24
 */
public class TankLogProxy implements Movable{
    Movable m;

    public TankLogProxy(Movable m) {
        this.m = m;
    }

    @Override
    public void move() {
        System.out.println("Start moving ....");
        m.move();
        System.out.println("End moving ....");
    }
}

TankTimeProxy

/**
 * @Author ChenJiahao(程序员五条)
 * @Date 2021/9/16 23:24
 */
public class TankTimeProxy implements Movable {
    Movable m;

    public TankTimeProxy(Movable m) {
        this.m = m;
    }

    @Override
    public void move() {
        long start = System.currentTimeMillis();
        m.move();
        long end = System.currentTimeMillis();
        System.out.println("移动时间为:" + (end - start) + "毫秒");
    }
}

4.1.4 测试类

/**
 * @Author ChenJiahao(程序员五条)
 * @Date 2021/9/16 23:27
 */
public class Test {
    public static void main(String[] args) {
        new TankTimeProxy(
                new TankLogProxy(
                        new Tank()
                )
        ).move();
    }
}

4.2 动态代理具体实现

4.2.1 Movable接口

/**
 * @Author ChenJiahao(程序员五条)
 * @Date 2021/9/16 23:23
 */
public interface Movable {
    void move();
}

4.2.2 Tank(实现Movable)

/**
 * @Author ChenJiahao(程序员五条)
 * @Date 2021/9/16 23:23
 */
public class Tank implements Movable {
    @Override
    public void move() {
        System.out.println("Tank moving claclacla....");
        try {
            // 随机睡眠10秒
            Thread.sleep(new Random().nextInt(10000));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

4.2.3 LogHandler(代理类,实现InvocationHandler接口)

注:这里的横切代码与业务逻辑不分离,扩展的例子中讲解了分离

/**
 * @Author ChenJiahao(程序员五条)
 * @Date 2021/9/16 23:24
 */
public class LogHandler implements InvocationHandler {
    Movable movable;

    public LogHandler(Movable movable) {
        this.movable = movable;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("method" + method.getName() + "start ...");
        Object o = method.invoke(movable,args);
        System.out.println("method" + method.getName() + "end!");
        return o;
    }
}

4.2.4 测试类

/**
 * @Author ChenJiahao(程序员五条)
 * @Date 2021/9/16 23:27
 */
public class Test {
    public static void main(String[] args) {
        Tank tank = new Tank();
        // Proxy.newProxyInstance使用方法,见"动态代理需要的类"中
        Movable m = (Movable) Proxy.newProxyInstance(Tank.class.getClassLoader(),
                new Class[]{Movable.class}, // tank.class.getInterfaces()
                new LogHandler(tank));
        m.move();
    }
}

5 扩展(AOP)

5.1 动态代理引入AOP的概念

与动态代理中的实例区别为:修改代理类中的invoke方法

before和after中的非业务逻辑本身是直接存在于invoke方法中的,现在抽离出来

将本来在invoke方法中写的非业务逻辑,抽离成一个个方法,去调用,这样结构就比较明确了,这就是Spring@Around环绕通知的原理了

5.2 引入AOP思想后的代码

修改动态代码中的LogHandler,将执行method.invoke()方法前的逻辑抽离出来

/**
 * @Author ChenJiahao(程序员五条)
 * @Date 2021/9/16 23:24
 */
public class LogHandler implements InvocationHandler {
    Movable movable;

    public LogHandler(Movable movable) {
        this.movable = movable;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        before(method);
        Object o = method.invoke(movable,args);
        after(method);
        return o;
    }

    private void after(Method method) {
        System.out.println("method" + method.getName() + "end!");
    }

    private void before(Method method) {
        System.out.println("method" + method.getName() + "start ...");
    }
}

6 思维导图

7 示例源码地址

https://github.com/ChenJiahao0205/design-pattern/tree/master

最后

我是通过马士兵老师的视频和菜鸟教程学习的,部分内容可能会有雷同

想阅读更多设计模式相关文章,欢迎到我的专栏【设计模式学习笔记】、【设计模式】中去查看

在23篇设计模式文章发布完成之后,我会公开完整的思维导图,点关注,不迷路

感谢大家看到这里,文章如有不足,欢迎大家指出;彦祖点个赞吧彦祖点个赞吧彦祖点个赞吧,欢迎关注程序员五条

你可能感兴趣的:(设计模式,#,设计模式学习笔记,设计模式,java,spring)