JDK动态代理
什么是动态代理:
- 使用java反射机制,根据代码结构自动创建代理类(.class)(不用程序员自身编写代码)。
为什么要是用动态代理:
- 可以在不改变原有目标方法功能的前提下,可以在代理中增强自己的功能的代码。
注意点:
- 被代理类,对应的方法必须要求实现接口。
- 被代理类调用的方法,如果不是通过实现接口而来的话,就需要使用cglib在实现动态代理。
jdk动态代理demo
/**
* 测试类
**/
public class JdkProxyDemo {
interface Foo{
void foo();
}
static final class Target implements Foo{
@Override
public void foo() {
System.out.println("target foo");
}
}
/**
* 1.jdk代理 只能针对接口代理
* @param args
*/
public static void main(String[] args) throws IOException {
// 目标对象
Target target = new Target();
ClassLoader loader = JdkProxyDemo.class.getClassLoader();//在运行期间动态生成的代理类
Foo proxy = (Foo)Proxy.newProxyInstance(loader, new Class[]{Foo.class}, (p, method, args1) -> {
System.out.println("before");
Object invoke = method.invoke(target, args1);
System.out.println("after");
return invoke;
});
System.out.println(proxy.getClass());
proxy.foo();
System.in.read();
}
}
jdk实现
public class Target {
interface Foo{
void foo();
int bar();
}
/**
* 被代理类
**/
static class TargetPorxy implements Target.Foo {
@Override
public void foo() {
System.out.println("target foo");
}
@Override
public int bar() {
System.out.println("target bar");
return 100;
}
}
// interface InvocationHandler{
// Object invoke(Object proxy, Method method, Object[] param) throws InvocationTargetException, IllegalAccessException;
// }
/**
* 1.jdk代理 只能针对接口代理
* @param args
*/
public static void main(String[] args) {
Foo proxy = new $Porxy0(new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] param) throws InvocationTargetException, IllegalAccessException {
// 1功能增强
System.out.println("before");
// 2 调用目标
return method.invoke(new TargetPorxy(), param);
}
});
proxy.foo();
proxy.bar();
}
}
/**
* 代理类
**/
public class $Porxy0 extends Proxy implements Foo {
// private InvocationHandler h;
public $Porxy0(InvocationHandler h) {
super(h);
}
@Override
public void foo() {
try {
h.invoke(this, foo, new Object[0]);
} catch (RuntimeException | Error error) {
throw error;
} catch (Throwable e){
throw new UndeclaredThrowableException(e);
}
}
@Override
public int bar() {
try {
Object invoke = h.invoke(this, bar, new Object[0]);
return (int)invoke;
} catch (RuntimeException | Error error) {
throw error;
} catch (Throwable e){
throw new UndeclaredThrowableException(e);
}
}
static Method foo;
static Method bar;
static {
try {
foo = Foo.class.getMethod("foo");
bar = Foo.class.getMethod("bar");
} catch (NoSuchMethodException e) {
throw new NoSuchMethodError(e.getMessage());
}
}
}
jdk自生成的代理类源码
使用 arthas 来查看
/*
* Decompiled
* with CFR.
*
* Could not load the following classes:
* com.dengsheng.a12.JdkProxyDemo$Foo
*/
package com.dengsheng.a12;
import com.dengsheng.a12.JdkProxyDemo;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
final class $Proxy0
extends Proxy
implements JdkProxyDemo.Foo {
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m0;
public $Proxy0(InvocationHandler invocationHandler) {
super(invocationHandler);
}
public final boolean equals(Object object) {
try {
return (Boolean)this.h.invoke(this, m1, new Object[]{object});
}
catch (Error | RuntimeException throwable) {
throw throwable;
}
catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final String toString() {
try {
return (String)this.h.invoke(this, m2, null);
}
catch (Error | RuntimeException throwable) {
throw throwable;
}
catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final void foo() {
try {
this.h.invoke(this, m3, null);
return;
}
catch (Error | RuntimeException throwable) {
throw throwable;
}
catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final int hashCode() {
try {
return (Integer)this.h.invoke(this, m0, null);
}
catch (Error | RuntimeException throwable) {
throw throwable;
}
catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m3 = Class.forName("com.dengsheng.a12.JdkProxyDemo$Foo").getMethod("foo", new Class[0]);
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
return;
}
catch (NoSuchMethodException noSuchMethodException) {
throw new NoSuchMethodError(noSuchMethodException.getMessage());
}
catch (ClassNotFoundException classNotFoundException) {
throw new NoClassDefFoundError(classNotFoundException.getMessage());
}
}
}
ASM字节码文件
生成代理对象(.class)的代码
package com.dengsheng.a12.proxy.asm;
import org.springframework.asm.*;
public class $Porxy0Dump implements Opcodes {
public static byte[] dump() throws Exception {
ClassWriter cw = new ClassWriter(0);
FieldVisitor fv;
MethodVisitor mv;
AnnotationVisitor av0;
// 52:java8, ACC_PUBLIC + ACC_SUPER:使用public 进行修饰, 类名,空,父类,实现接口
cw.visit(52, ACC_PUBLIC + ACC_SUPER, "com/dengsheng/a12/proxy/asm/$Porxy0", null, "java/lang/reflect/Proxy", new String[]{"com/dengsheng/a12/proxy/asm/Foo"});
cw.visitSource("$Porxy0.java", null);
{
// 静态成员变量
fv = cw.visitField(ACC_STATIC, "foo", "Ljava/lang/reflect/Method;", null, null);
fv.visitEnd();
}
{
// 静态成员变量
fv = cw.visitField(ACC_STATIC, "bar", "Ljava/lang/reflect/Method;", null, null);
fv.visitEnd();
}
{
// 构造方法
mv = cw.visitMethod(ACC_PUBLIC, "<init>", "(Ljava/lang/reflect/InvocationHandler;)V", null, null);
mv.visitParameter("h", 0);
mv.visitCode();
/**
* 字节码
*/
Label l0 = new Label();
mv.visitLabel(l0);
mv.visitLineNumber(11, l0);
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 1);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/reflect/Proxy", "<init>", "(Ljava/lang/reflect/InvocationHandler;)V", false);
Label l1 = new Label();
mv.visitLabel(l1);
mv.visitLineNumber(12, l1);
mv.visitInsn(RETURN);
Label l2 = new Label();
mv.visitLabel(l2);
mv.visitLocalVariable("this", "Lcom/dengsheng/a12/proxy/asm/$Porxy0;", null, l0, l2, 0);
mv.visitLocalVariable("h", "Ljava/lang/reflect/InvocationHandler;", null, l0, l2, 1);
mv.visitMaxs(2, 2);
mv.visitEnd();
}
{
mv = cw.visitMethod(ACC_PUBLIC, "foo", "()V", null, null);
mv.visitCode();
Label l0 = new Label();
Label l1 = new Label();
Label l2 = new Label();
mv.visitTryCatchBlock(l0, l1, l2, "java/lang/RuntimeException");
mv.visitTryCatchBlock(l0, l1, l2, "java/lang/Error");
Label l3 = new Label();
mv.visitTryCatchBlock(l0, l1, l3, "java/lang/Throwable");
mv.visitLabel(l0);
mv.visitLineNumber(17, l0);
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, "com/dengsheng/a12/proxy/asm/$Porxy0", "h", "Ljava/lang/reflect/InvocationHandler;");
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETSTATIC, "com/dengsheng/a12/proxy/asm/$Porxy0", "foo", "Ljava/lang/reflect/Method;");
mv.visitInsn(ICONST_0);
mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
mv.visitMethodInsn(INVOKEINTERFACE, "java/lang/reflect/InvocationHandler", "invoke", "(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;", true);
mv.visitInsn(POP);
mv.visitLabel(l1);
mv.visitLineNumber(22, l1);
Label l4 = new Label();
mv.visitJumpInsn(GOTO, l4);
mv.visitLabel(l2);
mv.visitLineNumber(18, l2);
mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[]{"java/lang/Throwable"});
mv.visitVarInsn(ASTORE, 1);
Label l5 = new Label();
mv.visitLabel(l5);
mv.visitLineNumber(19, l5);
mv.visitVarInsn(ALOAD, 1);
mv.visitInsn(ATHROW);
mv.visitLabel(l3);
mv.visitLineNumber(20, l3);
mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[]{"java/lang/Throwable"});
mv.visitVarInsn(ASTORE, 1);
Label l6 = new Label();
mv.visitLabel(l6);
mv.visitLineNumber(21, l6);
mv.visitTypeInsn(NEW, "java/lang/reflect/UndeclaredThrowableException");
mv.visitInsn(DUP);
mv.visitVarInsn(ALOAD, 1);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/reflect/UndeclaredThrowableException", "<init>", "(Ljava/lang/Throwable;)V", false);
mv.visitInsn(ATHROW);
mv.visitLabel(l4);
mv.visitLineNumber(23, l4);
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
mv.visitInsn(RETURN);
Label l7 = new Label();
mv.visitLabel(l7);
mv.visitLocalVariable("error", "Ljava/lang/Throwable;", null, l5, l3, 1);
mv.visitLocalVariable("e", "Ljava/lang/Throwable;", null, l6, l4, 1);
mv.visitLocalVariable("this", "Lcom/dengsheng/a12/proxy/asm/$Porxy0;", null, l0, l7, 0);
mv.visitMaxs(4, 2);
mv.visitEnd();
}
{
mv = cw.visitMethod(ACC_PUBLIC, "bar", "()I", null, null);
mv.visitCode();
Label l0 = new Label();
Label l1 = new Label();
Label l2 = new Label();
mv.visitTryCatchBlock(l0, l1, l2, "java/lang/RuntimeException");
mv.visitTryCatchBlock(l0, l1, l2, "java/lang/Error");
Label l3 = new Label();
mv.visitTryCatchBlock(l0, l1, l3, "java/lang/Throwable");
mv.visitLabel(l0);
mv.visitLineNumber(28, l0);
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, "com/dengsheng/a12/proxy/asm/$Porxy0", "h", "Ljava/lang/reflect/InvocationHandler;");
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETSTATIC, "com/dengsheng/a12/proxy/asm/$Porxy0", "bar", "Ljava/lang/reflect/Method;");
mv.visitInsn(ICONST_0);
mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
mv.visitMethodInsn(INVOKEINTERFACE, "java/lang/reflect/InvocationHandler", "invoke", "(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;", true);
mv.visitVarInsn(ASTORE, 1);
Label l4 = new Label();
mv.visitLabel(l4);
mv.visitLineNumber(29, l4);
mv.visitVarInsn(ALOAD, 1);
mv.visitTypeInsn(CHECKCAST, "java/lang/Integer");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false);
mv.visitLabel(l1);
mv.visitInsn(IRETURN);
mv.visitLabel(l2);
mv.visitLineNumber(30, l2);
mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[]{"java/lang/Throwable"});
mv.visitVarInsn(ASTORE, 1);
Label l5 = new Label();
mv.visitLabel(l5);
mv.visitLineNumber(31, l5);
mv.visitVarInsn(ALOAD, 1);
mv.visitInsn(ATHROW);
mv.visitLabel(l3);
mv.visitLineNumber(32, l3);
mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[]{"java/lang/Throwable"});
mv.visitVarInsn(ASTORE, 1);
Label l6 = new Label();
mv.visitLabel(l6);
mv.visitLineNumber(33, l6);
mv.visitTypeInsn(NEW, "java/lang/reflect/UndeclaredThrowableException");
mv.visitInsn(DUP);
mv.visitVarInsn(ALOAD, 1);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/reflect/UndeclaredThrowableException", "<init>", "(Ljava/lang/Throwable;)V", false);
mv.visitInsn(ATHROW);
Label l7 = new Label();
mv.visitLabel(l7);
mv.visitLocalVariable("invoke", "Ljava/lang/Object;", null, l4, l2, 1);
mv.visitLocalVariable("error", "Ljava/lang/Throwable;", null, l5, l3, 1);
mv.visitLocalVariable("e", "Ljava/lang/Throwable;", null, l6, l7, 1);
mv.visitLocalVariable("this", "Lcom/dengsheng/a12/proxy/asm/$Porxy0;", null, l0, l7, 0);
mv.visitMaxs(4, 2);
mv.visitEnd();
}
{
mv = cw.visitMethod(ACC_STATIC, "<clinit>", "()V", null, null);
mv.visitCode();
Label l0 = new Label();
Label l1 = new Label();
Label l2 = new Label();
mv.visitTryCatchBlock(l0, l1, l2, "java/lang/NoSuchMethodException");
mv.visitLabel(l0);
mv.visitLineNumber(41, l0);
mv.visitLdcInsn(Type.getType("Lcom/dengsheng/a12/proxy/asm/Foo;"));
mv.visitLdcInsn("foo");
mv.visitInsn(ICONST_0);
mv.visitTypeInsn(ANEWARRAY, "java/lang/Class");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getMethod", "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
mv.visitFieldInsn(PUTSTATIC, "com/dengsheng/a12/proxy/asm/$Porxy0", "foo", "Ljava/lang/reflect/Method;");
Label l3 = new Label();
mv.visitLabel(l3);
mv.visitLineNumber(42, l3);
mv.visitLdcInsn(Type.getType("Lcom/dengsheng/a12/proxy/asm/Foo;"));
mv.visitLdcInsn("bar");
mv.visitInsn(ICONST_0);
mv.visitTypeInsn(ANEWARRAY, "java/lang/Class");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getMethod", "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
mv.visitFieldInsn(PUTSTATIC, "com/dengsheng/a12/proxy/asm/$Porxy0", "bar", "Ljava/lang/reflect/Method;");
mv.visitLabel(l1);
mv.visitLineNumber(45, l1);
Label l4 = new Label();
mv.visitJumpInsn(GOTO, l4);
mv.visitLabel(l2);
mv.visitLineNumber(43, l2);
mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[]{"java/lang/NoSuchMethodException"});
mv.visitVarInsn(ASTORE, 0);
Label l5 = new Label();
mv.visitLabel(l5);
mv.visitLineNumber(44, l5);
mv.visitTypeInsn(NEW, "java/lang/NoSuchMethodError");
mv.visitInsn(DUP);
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/NoSuchMethodException", "getMessage", "()Ljava/lang/String;", false);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/NoSuchMethodError", "<init>", "(Ljava/lang/String;)V", false);
mv.visitInsn(ATHROW);
mv.visitLabel(l4);
mv.visitLineNumber(46, l4);
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
mv.visitInsn(RETURN);
mv.visitLocalVariable("e", "Ljava/lang/NoSuchMethodException;", null, l5, l4, 0);
mv.visitMaxs(3, 1);
mv.visitEnd();
}
cw.visitEnd();
// 生成byte数据,就是字节码
return cw.toByteArray();
}
}
使用如下代码可以生成 对应的代理对象(Proxy0),存放到jvm中,并生成Target类的代理对象
package com.dengsheng.a12.proxy.asm;
import java.io.FileOutputStream;
public class TestProxy {
public static class Target implements Foo {
@Override
public void foo() {
System.out.println("foo");
}
@Override
public int bar() {
System.out.println("bar");
return 100;
}
}
/**
* jvm加载asm生成的代理类的字节码,并调用被代理类的成员方法
**/
public static void main(String[] args) throws Exception {
byte[] dump = $Porxy0Dump.dump();
// 使用如下代码可以生成 对应的代理对象(Proxy0.class)
//FileOutputStream os = new FileOutputStream("$Proxy0.class");
//os.write(dump,0,dump.length);
//os.close();
ClassLoader loader = new ClassLoader() {
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
return super.defineClass(name, dump, 0, dump.length);
}
};
Class<?> proxyClass = loader.loadClass("com.dengsheng.a12.proxy.asm.$Porxy0");
Constructor<?> constructor = proxyClass.getConstructor(InvocationHandler.class);
Foo proxy = (Foo)constructor.newInstance(new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before...");
return method.invoke(target, args);
}
});
proxy.foo();
proxy.bar();
}
}