mybatis0060-jdk动态代理
作者:互联网
文章目录
githup项目地址
1. jdk动态代理是基于接口实现的
jdk的动态代理是基于接口实现的,所以一定要有接口,它可以实现两个功能 1)为接口生成一个实例对象 2)为实现接口的实例对象加入切面逻辑;
2. 为接口生成实例对象
假设有个MoveAble接口,意为可移动的,通过jdk的动态代理可以生成实现这个接口的实例。
2.1 MoveAble接口
public interface MoveAble {
void move();
}
2.2 调用处理程序 MoveAbleHandler
jdk生成的代理实例最终会调用这个类的invoke方法,相当于写在这个处理程序实现了原本应该由MoveAble实类实现的逻辑。
public class MoveAbleHandler implements InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("这边是代理做的工作");
return null;
}
}
2.3 测试类
public class Test {
public static void main(String[] args) throws Exception {
// 第一个参数是类加载器,用来加载生成的代理类
// 第二个参数是代理类实现的接口
// 第三个参数是调用处理程序
MoveAble moveAble = (MoveAble) Proxy.newProxyInstance(MoveAble.class.getClassLoader(), new Class[]{MoveAble.class}, new MoveAbleHandler());
moveAble.move();
}
}
2.4 结果
3. 执行过程分析
Proxy.newProxyInstance()方法最终会通过native方法生成代理对象
private static native Class<?> defineClass0(ClassLoader loader, String name,byte[] b, int off, int len);
通过jdk的sum.misc.ProxyGenerator类可以查看生成的字节码文件,如下配置
import java.io.File;
import java.io.FileOutputStream;
import java.lang.reflect.Proxy;
/**
* Created by rongyaowen
* on 2019/5/23.
*/
public class Test {
public static void main(String[] args) throws Exception {
// 第一个参数是类加载器,用来加载生成的代理类
// 第二个参数是代理类实现的接口
// 第三个参数是调用处理程序
MoveAble moveAble = (MoveAble) Proxy.newProxyInstance(MoveAble.class.getClassLoader(), new Class[]{MoveAble.class}, new MoveAbleHandler());
moveAble.move();
byte[] bts = ProxyGenerator.generateProxyClass("$MoveAble", Tank.class.getInterfaces());
FileOutputStream fos = new FileOutputStream(new File("E:/$MoveAble.class"));
fos.write(bts);
fos.flush();
fos.close();
}
}
将生成的字节码拉入idea中可以看到如下内容
import com.honor.proxy.MoveAble;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class $MoveAble extends Proxy implements MoveAble {
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m0;
public $MoveAble(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return ((Boolean)super.h.invoke(this, m1, new Object[]{var1})).booleanValue();
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final void move() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int hashCode() throws {
try {
return ((Integer)super.h.invoke(this, m0, (Object[])null)).intValue();
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")});
m3 = Class.forName("com.honor.proxy.MoveAble").getMethod("move", new Class[0]);
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
注:重写了equals、hashCode和toString方法。重点看move方法,move方法通过反射调用了父类的invoke方法。
return ((Boolean)super.h.invoke(this, m1, new Object[]{var1})).booleanValue();
super.h是什么呢?跟进去一看是
protected InvocationHandler h;
h是什么时候赋值的呢,当生成的代理实例初始化时,会将InvocationHandler对象赋值给proxy
public $MoveAble(InvocationHandler var1) throws {
super(var1);
}
那么初始化实例的时候传入的是什么值呢
return cons.newInstance(new Object[]{h});
这个h就是newProxyInstance传入得第三个参数,是调用处理程序
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
总结:通过newProxyInstance方法会生成一个实现了接口(第二个参数)的实例对象,这个对象实现了接口的方法,调用的是调用处理程序(第三个参数)的invoke方法。
4. 实现了接口的实例增加切面逻辑
4.1 上述Move接口不变
4.2 增加接口实现类 Tank
public class Tank implements MoveAble {
public void move() {
System.out.println("坦克移动。。。");
}
}
4.3 修改代理处理程序 TankHandler
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* Created by rongyaowen
* on 2019/5/23.
*/
public class TankHandler implements InvocationHandler {
// 传入实现了接口的实例,如这边的Tank实例
private MoveAble moveAble;
public TankHandler(MoveAble moveAble) {
this.moveAble = moveAble;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("代理开始");
Object object = method.invoke(moveAble, args);
System.out.println("代理结束");
return object;
}
}
4.4 测试
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
/**
* Created by rongyaowen
* on 2019/5/23.
*/
public class Test {
public static void main(String[] args) throws Exception {
Tank tank = new Tank();
InvocationHandler invocationHandler = new TankHandler(tank);
MoveAble moveAble = (MoveAble) Proxy.newProxyInstance(MoveAble.class.getClassLoader(), new Class[]{MoveAble.class},
invocationHandler);
moveAble.move();
}
}
4.5 结果
注:这边在代理执行程序中还执行了代理类的方法
Object object = method.invoke(moveAble, args);
4.6 调用过程
标签:mybatis0060,java,jdk,Object,代理,接口,MoveAble,new,public 来源: https://blog.csdn.net/wrongyao/article/details/90546409