栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

设计模式 结构型模式 -- 代理模式(动态代理(JDK动态代理(JDK动态代理要求必须定义接口,对接口进行代理。)、动态代理原理(使用arthas-boot.jar查看代理类的结构)、动态代理的作用)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

设计模式 结构型模式 -- 代理模式(动态代理(JDK动态代理(JDK动态代理要求必须定义接口,对接口进行代理。)、动态代理原理(使用arthas-boot.jar查看代理类的结构)、动态代理的作用)

  • 01:设计模式 结构型模式 – 代理模式(代理模式概述、结构、静态代理、动态代理)
  • 02: 设计模式 结构型模式 – 代理模式(动态代理(JDK动态代理(JDK动态代理要求必须定义接口,对接口进行代理。)、动态代理原理(使用arthas-boot.jar查看代理类的结构)、动态代理的作用)
  • 03: 设计模式 结构型模式 – 代理模式(动态代理(CGLIB动态代理)、三种代理的对比(静态代理、动态代理(JDK代理和CGLIB代理)、优缺点、使用场景))
1. 动态代理
1.1 JDK动态代理

【例】火车站卖票:

如果要买火车票的话,需要去火车站买票,坐车到火车站,排队等一系列的操作,显然比较麻烦。而火车站在多个地方都有代售点,我们去代售点买票就方便很多了。这个例子其实就是典型的代理模式,火车站是目标对象,代售点是代理对象。

接下来我们使用动态代理实现上面案例,先说说JDK提供的动态代理。Java中提供了一个动态代理类Proxy,Proxy并不是我们上述所说的代理对象的类,而是提供了一个创建代理对象的静态方法(newProxyInstance方法)来获取代理对象。

代码如下:

package com.tian;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

// 卖票接口
public interface SellTickets {
    void sell();
}

//火车站 火车站具有卖票功能,所以需要实现SellTickets接口 目标对象
class TrainStation implements SellTickets {
    public void sell() {
        System.out.println("火车站卖票");
    }
}

//代理工厂,用来创建代理对象


class ProxyFactory {
    //声明目标对象
    private final TrainStation station = new TrainStation();

    //获取代理对象的方法
    public SellTickets getProxyObject() {
        //返回代理对象
        
        return (SellTickets) Proxy.newProxyInstance(
                station.getClass().getClassLoader(),
                station.getClass().getInterfaces(),
                new InvocationHandler() {
                    
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("invoke方法执行了");
                        System.out.println("代售点收取一定的服务费用(jdk动态代理)");
                        //执行目标对象的方法
                        return method.invoke(station, args);
                    }
                }
        );
    }
}

// 测试类
class Client {
    public static void main(String[] args) {
        ProxyFactory factory = new ProxyFactory();
        SellTickets proxyObject = factory.getProxyObject();
        proxyObject.sell();
    }
}

示例:


1.2 JDK动态代理的原理

ProxyFactory是代理类吗?

  • ProxyFactory不是代理模式中所说的代理类,而代理类是程序在运行过程中动态的在内存中生成的类。通过阿里巴巴开源的 Java 诊断工具(Arthas【阿尔萨斯】)查看代理类的结构:

先修改下原理的测试类:

运行程序:


在jar包对应的资源目录打开命令行

执行jar包
java -jar 包名 我这里是 java -jar arthas-boot.jar

选择要查看的线程,这里我选择2号线程

使用jad 类名查看代理类的结构

我们把生成的信息复制过来

package com.sun.proxy;

import java.lang.annotation.Inherited;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy0
extends Proxy
implements Inherited {
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m0;

    public $Proxy0(InvocationHandler invocationHandler) {
        super(invocationHandler);
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
            m3 = Class.forName("java.lang.annotation.Inherited").getMethod("annotationType", new Class[0]);
            m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
            return;
        }
        catch (NoSuchMethodException noSuchMethodException) {
            throw new NoSuchMethodError(noSuchMethodException.getMessage());
        }
        catch (ClassNotFoundException classNotFoundException) {
            throw new NoClassDefFoundError(classNotFoundException.getMessage());
        }
    }

    public final boolean equals(Object object) {
        try {
            return (Boolean)this.h.invoke(this, m1, new Object[]{object});
        }
        catch (Error | RuntimeException throwable) {
            throw throwable;
        }
        catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    public final String toString() {
        try {
            return (String)this.h.invoke(this, m2, null);
        }
        catch (Error | RuntimeException throwable) {
            throw throwable;
        }
        catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    public final int hashCode() {
        try {
            return (Integer)this.h.invoke(this, m0, null);
        }
        catch (Error | RuntimeException throwable) {
            throw throwable;
        }
        catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }
    
    public final void sell () {
            try {
                this.h.invoke(this, m3, null);
                return;
            } catch (Error | RuntimeException throwable) {
                throw throwable;
            } catch (Throwable throwable) {
                throw new UndeclaredThrowableException(throwable);
            }
        }
}

我们过滤一下,保留主要的代码:

package com.sun.proxy;

public final class $Proxy0
extends Proxy
implements Inherited {
    private static Method m3;

    public $Proxy0(InvocationHandler invocationHandler) {
        super(invocationHandler);
    }

    static {
            m3 = Class.forName("java.lang.annotation.Inherited").getMethod("annotationType", new Class[0]);
    }

public final void sell() { this.h.invoke(this, m3, null); }
}

执行流程如下:

  1. 在测试类中通过代理对象调用sell()方法
  2. 根据多态的特性,执行的是代理类($Proxy0)中的sell()方法
  3. 代理类($Proxy0)中的sell()方法中又调用了InvocationHandler接口的子实现类对象的invoke方法
  4. invoke方法通过反射执行了真实对象所属类(TrainStation)中的sell()方法

1.3 动态代理的作用:

Java动态代理的优势是实现无侵入式的代码扩展,也就是方法的增强;让你可以在不用修改源码的情况下,增强一些方法;在方法的前后你可以做你任何想做的事情(甚至不去执行这个方法就可以)。



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/322105.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号