java jdk动态代理

JDK动态代理

什么是动态代理:

  1. 使用java反射机制,根据代码结构自动创建代理类(.class)(不用程序员自身编写代码)。

为什么要是用动态代理:

  1. 可以在不改变原有目标方法功能的前提下,可以在代理中增强自己的功能的代码。

注意点:

  1. 被代理类,对应的方法必须要求实现接口。
  2. 被代理类调用的方法,如果不是通过实现接口而来的话,就需要使用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();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值