模拟 jdk 动态代理
版本1.0
package com.butch.a12;
public class A12 {
//目标类和代理类都需要实现的公共接口
interface Foo{
void foo();
}
//目标类
static class Target implements Foo{
@Override
public void foo() {
System.out.println("target foo");
}
public static void main(String[] args) {
Foo foo = new $Proxy0();
foo.foo();
}
}
}
package com.butch.a12;
//代理类
public class $Proxy0 implements A12.Foo {
@Override
public void foo() {
//增强功能
System.out.println("========before=========");
//调用目标
new A12.Target().foo();
}
}
可以看到代码将增强的功能和目标方法调用写死到了代理中,可用性很差,版本二将增强和目标方法分离
版本2.0
package com.butch.a12;
public class A12 {
//目标类和代理类都需要实现的公共接口
interface Foo{
void foo();
}
//目标类
static class Target implements Foo {
@Override
public void foo() {
System.out.println("target foo");
}
}
//2.0解耦的关键接口
interface InvocationHandler{
void invoke();
}
public static void main(String[] args) {
//2.0这里就必须通过有参构造器实例化invcationhandle,在实现的invoke方法中自定义增强逻辑,注意要使用我们自己定义接口
Foo proxy = new $Proxy0(new InvocationHandler() {
@Override
public void invoke() {
//增强功能
System.out.println("========before=========");
//调用目标
new A12.Target().foo();
}
});
proxy.foo();
}
}
package com.butch.a12;
//代理类
public class $Proxy0 implements A12.Foo {
//2.0增加InvocationHandler处理
private A12.InvocationHandler h;
//2.0通过有参构造器实例化
public $Proxy0(A12.InvocationHandler h) {
this.h = h;
}
@Override
public void foo() {
//2.0在这里调用 接口的代理方法
h.invoke();
}
}
理解一下InvocationHandler
-
在代理类中定义成员变量,类型为InvocationHandler,并且提供唯一构造器,参数为InvocationHandler
-
当要创建代理类对象的时,就必须通过带有InvocationHandler的构造器实例化,就必须重写接口的invoke
-
在invoke实现增强的逻辑,调用目标方法
-
当使用代理类对象调用目标方法,就是去执行实例化代理类时InvocationHandler的增强逻辑了
但是此时如果公共接口新增了一个方法,被调用的时候也需要增强,2.0版本明显不能满足需求
版本3.0
package com.butch.a12;
import java.lang.reflect.Method;
//代理类
public class $Proxy0 implements A12.Foo {
//2.0增加InvocationHandler处理
private A12.InvocationHandler h;
//2.0通过有参构造器实例化
public $Proxy0(A12.InvocationHandler h) {
this.h = h;
}
@Override
public void foo() {
//3.0使用反射调用对应的方法,以增强不同的方法
Method foo = null;
try {
foo = A12.Foo.class.getDeclaredMethod("foo");
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
//2.0在这里调用 接口的代理方法
h.invoke(foo,new Object[0]);
}
@Override
public void bar() {
//3.0使用反射调用对应的方法,以增强不同的方法
Method bar = null;
try {
bar = A12.Foo.class.getDeclaredMethod("bar");
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
//3.0增加方法
h.invoke(bar,new Object[0]);
}
}
package com.butch.a12;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class A12 {
//目标类和代理类都需要实现的公共接口
interface Foo{
void foo();
//3.0增加方法
void bar();
}
//目标类
static class Target implements Foo {
//3.0增加方法
@Override
public void bar() {
System.out.println("target bar");
}
@Override
public void foo() {
System.out.println("target foo");
}
}
//2.0解耦的关键接口
interface InvocationHandler{
void invoke(Method method,Object[] objects);
}
public static void main(String[] args) {
//2.0这里就必须通过有参构造器实例化invcationhandle,在实现的invoke方法中自定义增强逻辑,注意要使用我们自己定义接口
Foo proxy = new $Proxy0(new InvocationHandler() {
@Override
public void invoke(Method method,Object[] Obj) {
//增强功能
System.out.println("========before=========");
//调用目标
try {
method.invoke(new Target(),Obj);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
});
proxy.foo();
proxy.bar();
}
}
3.0使用到反射去调用对应的目标方法,很好的适配了不同方法的增强,4.0将新增返回结果的目标方法及代码的精简
版本4.0
-
处理返回参数,并抛出异常
-
将反射匹配调用目标方法放入静态代码块中
-
在InvocationHandler中 新增参数Object proxy
-
使用jdk提供的InvocationHandler替换,并且代理类继承proxy
package com.butch.a12;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class A12 {
//目标类和代理类都需要实现的公共接口
interface Foo{
void foo();
//3.0增加方法
//4.0将方法变为有返回值的
int bar();
}
//目标类
static class Target implements Foo {
//3.0增加方法
@Override
public int bar() {
System.out.println("target bar");
return 100;
}
@Override
public void foo() {
System.out.println("target foo");
}
}
//2.0解耦的关键接口
// interface InvocationHandler{
// //4.0解耦的接口新增返回参数
// Object invoke(Object proxy,Method method,Object[] objects) throws Throwable;
// }
public static void main(String[] args) {
//2.0这里就必须通过有参构造器实例化invcationhandle,在实现的invoke方法中自定义增强逻辑,注意要使用我们自己定义接口
Foo proxy = new $Proxy0(new InvocationHandler() {
@Override
public Object invoke(Object proxy,Method method,Object[] Obj) throws Throwable {
//增强功能
System.out.println("========before=========");
//调用目标
//返回到代理类中
return method.invoke(new Target(),Obj);
}
});
proxy.foo();
proxy.bar();
}
}
package com.butch.a12;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
//代理类
public class $Proxy0 extends Proxy implements A12.Foo {
//2.0增加InvocationHandler处理
private InvocationHandler h;
//2.0通过有参构造器实例化
//4.0
public $Proxy0(InvocationHandler h) {
super(h);
}
@Override
public void foo() {
//3.0使用反射调用对应的方法,以增强不同的方法
// Method foo = null;
// try {
// foo = A12.Foo.class.getDeclaredMethod("foo");
// } catch (NoSuchMethodException e) {
// e.printStackTrace();
// }
// //2.0在这里调用 接口的代理方法
try {
h.invoke(this,foo,new Object[0]);
} catch (RuntimeException | Error e) {
throw e;
} catch (Throwable e) {
throw new UndeclaredThrowableException(e);
}
}
@Override
public int bar() {
//3.0使用反射调用对应的方法,以增强不同的方法
// Method bar = null;
// try {
// bar = A12.Foo.class.getDeclaredMethod("bar");
// } catch (NoSuchMethodException e) {
// e.printStackTrace();
// }
//3.0增加方法
try {
Object invoke = h.invoke(this,bar, new Object[0]);
return (int)invoke;
} catch (RuntimeException | Error e) {
throw e;
} catch (Throwable e) {
throw new UndeclaredThrowableException(e);
}
}
//4.0
static Method foo;
static Method bar;
static {
try {
foo = A12.Foo.class.getMethod("foo");
bar = A12.Foo.class.getMethod("bar");
} catch (NoSuchMethodException e) {
throw new NoSuchMethodError(e.getMessage());
}
}
}
流程
-
初始化代理对象,需要通过构造器InvocationHandler,在重写方法中定义增强逻辑,然后根据反射方法参数调用代理方法
-
使用代理对象调用增强方法,回调到InvocationHandler的重写方法中,执行增强逻辑,执行代理的增强方法,进入代理类
-
通过反射调用,执行目标方法的增强方法
总结
jdk代理实现原理
-
方法重写可以增强逻辑,只不过这【增强逻辑】千变万化,不能写死在代理内部
-
通过接口回调将【增强逻辑】置于代理类之外
-
配合接口方法反射(是多态调用),就可以再联动调用目标方法
-
会用 arthas 的 jad 工具反编译代理类
-
限制⛔:代理增强是借助多态来实现,因此成员变量、静态方法、final 方法均不能通过代理实现
方法反射优化
package com.butch.a12;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
// 运行时请添加 --add-opens java.base/java.lang.reflect=ALL-UNNAMED --add-opens java.base/jdk.internal.reflect=ALL-UNNAMED
public class TestMethodInvoke {
public static void main(String[] args) throws Exception {
Method foo = TestMethodInvoke.class.getMethod("foo", int.class);
for (int i = 1; i <= 17; i++) {
show(i, foo);
foo.invoke(null, i);
}
System.in.read();
}
// 方法反射调用时, 底层 MethodAccessor 的实现类
private static void show(int i, Method foo) throws Exception {
Method getMethodAccessor = Method.class.getDeclaredMethod("getMethodAccessor");
getMethodAccessor.setAccessible(true);
Object invoke = getMethodAccessor.invoke(foo);
if (invoke == null) {
System.out.println(i + ":" + null);
return;
}
Field delegate = Class.forName("jdk.internal.reflect.DelegatingMethodAccessorImpl").getDeclaredField("delegate");
delegate.setAccessible(true);
System.out.println(i + ":" + delegate.get(invoke));
}
public static void foo(int i) {
System.out.println(i + ":" + "foo");
}
}
-
前 16 次反射性能较低
-
第 17 次调用会生成代理类,优化为非反射调用
-
会用 arthas 的 jad 工具反编译第 17 次调用生成的代理类