代理模式是指在对象行为发生前后添加处理逻辑且零修改。
1.静态代理
/**
* 排序的接口
* */
public interface Sort {
public void sort(int[] arr);
}
/**
* 插入排序
* */
public class InsertSort implements Sort{
public void swap(int[] arr,int i,int j){
if(i==j){
return;
}
arr[i] = arr[i]^arr[j];
arr[j] = arr[i]^arr[j];
arr[i] = arr[i]^arr[j];
};
@Override
public void sort(int[] arr) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
if(arr==null||arr.length<2) return;
for(int i =0;i<arr.length-1;i++){
for(int j = i+1;j>0&&arr[j]<arr[j-1];j--){
swap(arr,j-1,j);
}
}
}
}
/**
* 插入排序代理类
* */
public class InsertSortProxy implements Sort{
Sort sort;
public InsertSortProxy(Sort sort){
this.sort=sort;
}
@Override
public void sort(int[] arr) {
long start = new Date().getTime();
sort.sort(arr);
long end = new Date().getTime();
System.out.println(end-start);
}
}
public class Main {
public static void main(String[] args) {
int[] arr = {3,5,6,8,2,4,5,1,7,8};
//new InsertSort().sort(arr);
new InsertSortProxy(new InsertSort()).sort(arr);
}
}
可以看到,上述通过组合实现了零修改添加新的业务逻辑。
虽然与装饰器模式的代码看起来类似,但实际上差别很大。装饰器本质是拓展新方法,而代理更多的是为原来的被代理对象的方法执行前后新逻辑。
2.动态代理:
2.1 JDK实现动态代理
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Date;
public class Main {
public static void main(String[] args) {
int[] arr = {3,5,6,8,2,4,5,1,7,8};
//第一个参数:被代理对象的类加载器 第二个参数:被代理对象需要代理的方法所在接口的类数组 第三个参数:一个InvocationHandler对象
Sort sort = (Sort) Proxy.newProxyInstance(InsertSort.class.getClassLoader(), new Class[]{Sort.class}, new InvocationHandler() {
//通过匿名内部类的方式,产生对象,该对象实现了InvocationHandler接口
//第一个参数 是Java动态产生的代理类对象,第二个参数是方法对象,第三个参数是第二个对象的参数
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
long start = new Date().getTime();
method.invoke(new InsertSort(),args);
long end = new Date().getTime();
System.out.println(end-start);
return null;
}
});
sort.sort(arr);
}
}
JDK实现的动态代理,本质上是通过ASM技术在内存中生成一个新的类$PROXY0.class。
这个类和我们静态代理自己定义的类相似,它和我们的代理类InsertSort同样实现了Sort接口,并在其内部实现了Sort接口所有方法。
当我们执行完Proxy.newProxyInstance()方法后返回的就是这个代理类对象。
以下,是该类的源码
import Proxy.Sort;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
/**
* 继承了Proxy,并实现了Sort
*/
public final class $Proxy0 extends Proxy implements Sort {
//定义方法对象,为了保证后续调用方法时一一对应
private static final Method m0;
private static final Method m1;
private static final Method m2;
private static final Method m3;
private static final Method m4;
static {
ClassLoader var0 = $Proxy0.class.getClassLoader();
try {
m0 = Class.forName("java.lang.Object", false, var0).getMethod("hashCode");
m1 = Class.forName("java.lang.Object", false, var0).getMethod("equals", Class.forName("java.lang.Object", false, var0));
m2 = Class.forName("java.lang.Object", false, var0).getMethod("toString");
//通过反射拿到sort方法和swap方法的对象
m3 = Class.forName("Proxy.Sort", false, var0).getMethod("sort", Class.forName("[I", false, var0));
m4 = Class.forName("Proxy.Sort", false, var0).getMethod("swap", Class.forName("[I", false, var0), Integer.TYPE, Integer.TYPE);
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
//注入InvocationHandler对象,InvocationHandler的定义在他的父类Proxy
public $Proxy0(InvocationHandler var1) {
//此时注入的是NewInstance()方法中第三个参数传入的InvocationHandler对象
super(var1);
}
public final int hashCode() {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final boolean equals(Object var1) {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final String toString() {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
//这是代理对象实现Sort接口的sort方法
public final void sort(int[] var1) {
try {
//执行的是创建代理对象时注入的InvocationHandler对象的invoke方法,也就是我们实现的匿名内部类里的invoke方法。
//第二个参数传入的是m3,由上可知,传入的是Sort接口的sort方法
//也就是说,此时我们执行了自己前后加工的逻辑后,还执行了Sort.sort()的Method对象的invoke()方法。
//method.invoke(new InsertSort(),args);
//此时也就是因为传入的对象是被代理对象,所以此处调用的就是被代理对象的sort方法
super.h.invoke(this, m3, new Object[]{var1});
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
//同理,此处invoke传入的方法对象m4也就是上面初始化时定义的swap方法
public final void swap(int[] var1, int var2, int var3) {
try {
super.h.invoke(this, m4, new Object[]{var1, var2, var3});
} catch (RuntimeException | Error var4) {
throw var4;
} catch (Throwable var5) {
throw new UndeclaredThrowableException(var5);
}
}
}
2.2 Cglib实现动态代理
Cglib是第三方jar包,实现思路是通过继承的方式获得被代理类的方法然后前后组装新的逻辑。大体思路是一样的。这里不多描述