spring 11 jdk 动态代理进阶
jdk 动态代理进阶
模拟 jdk 动态代理
点击查看代码
public static void main(String[] args) {
B b = new B();
A proxyInstance = (A) new $Proxy0(new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before...");
Object result = method.invoke(b, args);
System.out.println("after...");
return result;
}
});
proxyInstance.a();
proxyInstance.b();
}
模拟代理实现
// Proxy 类中含有 protected 属性 InvocationHandler
public class $Proxy0 extends Proxy implements A{
// private java.lang.reflect.InvocationHandler h;
static Method a;
static Method b;
static {
try {
a = A.class.getMethod("a");
b = A.class.getMethod("b");
} catch (NoSuchMethodException e) {
throw new NoSuchMethodError(e.getMessage()); //静态代码块错误,说明错误很严重,用 Error.
}
}
@Override
public int a() {
try {
Object result = h.invoke(this, a, new Object[0]);
return (int) result;
} catch (RuntimeException | Error e) {
throw e; //运行时异常可直接抛出
} catch (Throwable e) {
throw new UndeclaredThrowableException(e);
}
}
@Override
public int b() {
try {
Object result = h.invoke(this, b, new Object[0]);
return (int) result;
}catch (RuntimeException | Error e){
throw e;
}catch (Throwable e){
throw new UndeclaredThrowableException(e);
}
}
public $Proxy0(InvocationHandler h) {
super(h);
// this.invocationHandler = invocationHandler;
}
}
// 如果 b 方法有参数,更改即可。
public int b(int i) {
try {
Object result = h.invoke(this, b, new Object[]{i});
return (int) result;
}catch (RuntimeException | Error e){
public interface A {
int a();
int b();
}
public class B implements A{
@Override
public int a() {
System.out.println("B a running...");
return 57;
}
@Override
public int b() {
System.out.println("B b running...");
return 58;
}
}
public interface InvocationHandler {
Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
代理一点都不难,无非就是利用了多态、反射的知识
- 方法重写可以增强逻辑,只不过这【增强逻辑】千变万化,不能写死在代理内部
- 通过接口回调将【增强逻辑】置于代理类之外
- 配合接口方法反射(是多态调用),就可以再联动调用目标方法
- 会用 arthas 的 jad 工具反编译代理类, jdk 动态代理生成的代理类直接就是字节码,没有源代码,所有要借助工具查看。(运用 ASM 技术,用于很多框架)
- 限制⛔:代理增强是借助多态来实现,因此成员变量、静态方法、final 方法均不能通过代理实现
方法反射优化
- 前 16 次反射性能较低
- 第 17 次调用会生成代理类,优化为非反射调用,一个方法优化生成一个代理类。两个方法就是两个。而 cjlib 中一个类的所有方法的优化生成两个代理类就行。
- 会用 arthas 的 jad 工具反编译第 17 次调用生成的代理类
注意
运行时请添加 --add-opens java.base/java.lang.reflect=ALL-UNNAMED --add-opens java.base/jdk.internal.reflect=ALL-UNNAMED
arthas 的使用
参考:https://blog.csdn.net/u012002125/article/details/125066186