设计模式 结构型模式 -- 代理模式(动态代理(JDK动态代理(JDK动态代理要求必须定义接口,对接口进行代理。)动态代理原理(使用arthas-boot.jar查看代理类的结构)动态代理的作用)(代
Posted Z && Y
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式 结构型模式 -- 代理模式(动态代理(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("火车站卖票");
}
}
//代理工厂,用来创建代理对象
/**
* @version v1.0
* @ClassName: ProxyFactory
* @Description: 获取代理对象的工厂类
* 代理类也实现了对应的接口
*/
class ProxyFactory {
//声明目标对象
private final TrainStation station = new TrainStation();
//获取代理对象的方法
public SellTickets getProxyObject() {
//返回代理对象
/*
ClassLoader loader : 类加载器,用于加载代理类。可以通过目标对象获取类加载器
Class<?>[] interfaces : 代理类实现的接口的字节码对象
InvocationHandler h : 代理对象的调用处理程序
*/
return (SellTickets) Proxy.newProxyInstance(
station.getClass().getClassLoader(),
station.getClass().getInterfaces(),
new InvocationHandler() {
/*
Object proxy : 代理对象。和proxyObject对象是同一个对象,在invoke方法中基本不用
Method method : 对接口中的方法进行封装的method对象
Object[] args : 调用方法的实际参数
返回值: 方法的返回值。
*/
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); }
}
执行流程如下:
- 在测试类中通过代理对象调用sell()方法
- 根据多态的特性,执行的是代理类($Proxy0)中的sell()方法
- 代理类($Proxy0)中的sell()方法中又调用了InvocationHandler接口的子实现类对象的invoke方法
- invoke方法通过反射执行了真实对象所属类(TrainStation)中的sell()方法
1.3 动态代理的作用:
Java动态代理的优势是实现无侵入式的代码扩展,也就是方法的增强;让你可以在不用修改源码的情况下,增强一些方法;在方法的前后你可以做你任何想做的事情(甚至不去执行这个方法就可以)。
以上是关于设计模式 结构型模式 -- 代理模式(动态代理(JDK动态代理(JDK动态代理要求必须定义接口,对接口进行代理。)动态代理原理(使用arthas-boot.jar查看代理类的结构)动态代理的作用)(代的主要内容,如果未能解决你的问题,请参考以下文章
设计模式 结构型模式 -- 代理模式(动态代理(JDK动态代理(JDK动态代理要求必须定义接口,对接口进行代理。)动态代理原理(使用arthas-boot.jar查看代理类的结构)动态代理的作用)(代