代理要解决的问题
如何调用到被代理类的原始方法?
jdk代理代码
package jdk代理;
/***
* @author: claude
* @date: 2023/3/1
* @description:
*/
public interface AddAndSubCalculator {
/***
* 加法
* @param i
* @param j
* @return
*/
public int add(int i, int j);
/***
* 减法
* @param i
* @param j
* @return
*/
public int sub(int i, int j);
}
package jdk代理;
/***
* @author: claude
* @date: 2023/3/1
* @description:
*/
public interface MultiplyAndDivCalculator {
/****
* 乘法
* @param i
* @param j
* @return
*/
public int multiply(int i, int j);
/****
* 除法
* @param i
* @param j
* @return
*/
public int div(int i, int j);
}
package jdk代理;
/***
* @author: claude
* @date: 2023/3/1
* @description:
*/
public class CalculatorConcrete implements AddAndSubCalculator, MultiplyAndDivCalculator {
@Override
public int add(int i, int j) {
int result = i + j;
System.out.println("计算结果:" + result);
return result;
}
@Override
public int sub(int i, int j) {
int result = i - j;
System.out.println("计算结果:" + result);
return result;
}
@Override
public int multiply(int i, int j) {
int result = i * j;
System.out.println("计算结果:" + result);
return result;
}
@Override
public int div(int i, int j) {
int result = i / j;
System.out.println("计算结果:" + result);
return result;
}
}
package jdk代理;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* @author: claude-彭方亮
* @package: jdk代理.MyInvocationHandler
* @date: 2023/3/1 7:55
* @description:
* @version: 1.0
*/
public class CalculatorInvocationHandler implements InvocationHandler {
private CalculatorConcrete calculatorConcrete;
public CalculatorInvocationHandler(CalculatorConcrete calculatorConcrete) {
this.calculatorConcrete = calculatorConcrete;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("开始计算");
Object result = method.invoke(calculatorConcrete, args);
System.out.println("结束计算:" + result);
return result;
}
}
package jdk代理;
import java.lang.reflect.Proxy;
/***
* @author: claude
* @date: 2023/3/1
* @description:
*/
public class CalculatorProxyFactory{
public static Object getProxy(CalculatorConcrete calculator) {
ClassLoader loader = calculator.getClass().getClassLoader();
Class<?>[] interfaces = calculator.getClass().getInterfaces();
CalculatorInvocationHandler h = new CalculatorInvocationHandler(calculator);
Object proxy = Proxy.newProxyInstance(loader, interfaces, h);
return proxy;
}
public static void main(String[] args) {
AddAndSubCalculator addAndSubCalculator = (AddAndSubCalculator) getProxy(new CalculatorConcrete());
MultiplyAndDivCalculator multiplyAndDivCalculator = (MultiplyAndDivCalculator) getProxy(new CalculatorConcrete());
addAndSubCalculator.add(1, 1);
System.out.println("----------------------------");
multiplyAndDivCalculator.div(4, 4);
}
}
jdk代理原理概览
1.所有通过jdk代理生成的代理类会继承Proxy,在Proxy中有类型为InvocationHandler的成员变量。
protected InvocationHandler h;
Proxy中存在1个带参构造方法,参数是InvocationHandler。
Proxy(InvocationHandler h) {
Objects.requireNonNull(h);
this.h = h;
}
2.在CalculatorInvocationHandler中我们自定义了一个成员变量calculatorConcrete,为被代理类的实例。
3.调用Proxy.newProxyInstance(loader, interfaces, invocationHandler);
会把CalculatorInvocationHandler作为参数调用代理类的构造方法构建1个Proxy对象并返回,这就是我们的代理类对象。
同时由于我们的代理类继承了Proxy,所以CalculatorInvocationHandler可以通过super.h访问到。
4.在生成的代理类中会使用反射获取到代理类的接口的method对象,并作为代理类的成员变量。
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m4;
private static Method m5;
private static Method m6;
private static Method m0;
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("jdk代理.AddAndSubCalculator").getMethod("add", Integer.TYPE, Integer.TYPE);
m4 = Class.forName("jdk代理.AddAndSubCalculator").getMethod("sub", Integer.TYPE, Integer.TYPE);
m5 = Class.forName("jdk代理.MultiplyAndDivCalculator").getMethod("multiply", Integer.TYPE, Integer.TYPE);
m6 = Class.forName("jdk代理.MultiplyAndDivCalculator").getMethod("div", Integer.TYPE, Integer.TYPE);
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
5.生成的代理类会继承Proxy并实现AddAndSubCalculator, MultiplyAndDivCalculator接口。
并重写AddAndSubCalculator, MultiplyAndDivCalculator接口的所有方法,以add方法为例实现如下:
public final int add(int var1, int var2) throws {
try {
//super是Proxy,h是CalculatorInvocationHandler
//this是代理类对象
//m3是接口AddAndSubCalculator#add方法
//new Object[]{var1, var2}是入参
return (Integer)super.h.invoke(this, m3, new Object[]{var1, var2});
} catch (RuntimeException | Error var4) {
throw var4;
} catch (Throwable var5) {
throw new UndeclaredThrowableException(var5);
}
}
所以在调用代理类的方法时,调用的总是CalculatorInvocationHandler的invoke方法。
所以在调用代理类的方法时,调用的总是CalculatorInvocationHandler的invoke方法。
所以在调用代理类的方法时,调用的总是CalculatorInvocationHandler的invoke方法。
6.在CalculatorInvocationHandler#invoke方法中,我们可以使用被代理类的实例使用反射调用到被代理类的原始方法。
public class CalculatorInvocationHandler implements InvocationHandler {
private CalculatorConcrete calculatorConcrete;
public CalculatorInvocationHandler(CalculatorConcrete calculatorConcrete) {
this.calculatorConcrete = calculatorConcrete;
}
//参数1:即代理类对象
//参数2:即m3,是接口AddAndSubCalculator#add方法
//参数3:new Object[]{var1, var2}是入参
//calculatorConcrete是CalculatorInvocationHandler的成员变量
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("开始计算");
Object result = method.invoke(calculatorConcrete, args);
System.out.println("结束计算:" + result);
return result;
}
}
7.通过invocationHandler#invoke方法在原始类的原始方法前后动态织入代码。