[Jvm]程序员的精进之路~JDK代理源码初探

从模仿到反编译 jdk 代理源码

Jdk代理的最简单模拟, 由前文可知 JDK动态代理需要实现接口,所以基于此,进行最简单的模拟。

package com.example.proxy;

public class Jdk {

    interface Foo {
        void foo();
    }


    static class Target implements Foo {

        @Override
        public void foo() {
            System.out.println("foo");
        }
    }

    // 代理类
    static class $Proxy0 implements Foo {

        @Override
        public void foo() {
            // 1. 功能增强
            System.out.println("before");
            // 2. 调用目标
            new Target().foo();
        }
    }

    public static void main(String[] args) {
        Foo f = new $Proxy0();
        f.foo();
    }
}

虽然简单实现了代理,但是目前增强是固定的,但是在实际应用中,使用到代理类,方法是不可能固定的,所以接下来进行优化一下。使用抽象类+模版方法设置代理的执行逻辑。

package com.example.proxy;

public class Jdk {

    interface Foo {
        void foo();
    }



    static abstract class InvokeHandler {
        abstract Object invoke();
    }

    // 代理类
    static class $Proxy0 implements Foo {

        private final InvokeHandler invokeHandler;

        $Proxy0(InvokeHandler invokeHandler) {
            this.invokeHandler = invokeHandler;
        }

        @Override
        public void foo() {
            // 1. 功能增强
            System.out.println("before");
            // 2. 调用目标
            invokeHandler.invoke();
        }
    }
    

    public static void main(String[] args) {
        Foo f = new $Proxy0(new InvokeHandler() {
            @Override
            Object invoke() {
                System.out.println(">>>>>>>> foo");
                return null;
            }
        });
        f.foo();
    }
}

至此,方法就是可以不再固定。但是很显然,代理的对象不可能永远只有一个方法,所以想办法动态设置。

package com.example.proxy;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Jdk {

    interface Foo {
        void foo() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException;

        void bar() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException;
    }



    static abstract class InvokeHandler {
        abstract Object invoke(Method method, Object[] params) throws InvocationTargetException, IllegalAccessException;
    }

    // 代理类
    static class $Proxy0 implements Foo {

        private final InvokeHandler invokeHandler;

        $Proxy0(InvokeHandler invokeHandler) {
            this.invokeHandler = invokeHandler;
        }

        @Override
        public void foo() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
            // 1. 功能增强
            System.out.println("before");
            // 2. 调用目标
            invokeHandler.invoke(Foo.class.getMethod("foo"), new Object[0]);
        }

        @Override
        public void bar() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
            // 1. 功能增强
            System.out.println("before");
            // 2. 调用目标
            invokeHandler.invoke(Foo.class.getMethod("bar"), new Object[0]);
        }
    }

    static class Target implements Foo {
        @Override
        public void foo() {
            System.out.println("target foo");
        }

        @Override
        public void bar() {
            System.out.println("target bar");
        }
    }


    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Foo f = new $Proxy0(new InvokeHandler() {
            @Override
            Object invoke(Method method, Object[] params) throws InvocationTargetException, IllegalAccessException {
                // 传入代理对象
                method.invoke(new Target(), params);
                return null;
            }

        });
        f.foo();
        f.bar();
    }
}

/**
运行结果
before
target foo
before
target bar
**/

到这里,可以发现,多方法的代理对象也可以正常执行。但是如果执行方法有值返回呢,这个也简单,小修改一波。

package com.example.proxy;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Jdk {

    interface Foo {
        Object foo() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException;

        Object bar() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException;
    }



    static abstract class InvokeHandler {
        abstract Object invoke(Method method, Object[] params) throws InvocationTargetException, IllegalAccessException;
    }

    // 代理类
    static class $Proxy0 implements Foo {

        private final InvokeHandler invokeHandler;

        $Proxy0(InvokeHandler invokeHandler) {
            this.invokeHandler = invokeHandler;
        }

        @Override
        public Object foo() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
            // 1. 功能增强
            System.out.println("before");
            // 2. 调用目标
            return invokeHandler.invoke(Foo.class.getMethod("foo"), new Object[0]);
        }

        @Override
        public Object bar() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
            // 1. 功能增强
            System.out.println("before");
            // 2. 调用目标
            return invokeHandler.invoke(Foo.class.getMethod("bar"), new Object[0]);
        }
    }

    static class Target implements Foo {
        @Override
        public Integer foo() {
            System.out.println("target foo");
            return 1;
        }

        @Override
        public String  bar() {
            System.out.println("target bar");
            return "hello";
        }
    }


    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Foo f = new $Proxy0(new InvokeHandler() {
            @Override
            Object invoke(Method method, Object[] params) throws InvocationTargetException, IllegalAccessException {
                // 传入代理对象
                return method.invoke(new Target(), params);
            }

        });
        System.out.println(f.foo());
        System.out.println(f.bar());
    }
}

/**
运行结果
before
target foo
1
before
target bar
hello

**/

在源码实现中,方法还可以被缓存复用,不需要每次都重新创建。

package com.example.proxy;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

public class Jdk {

    interface Foo {
        Object foo() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException;

        Object bar() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException;
    }



    static abstract class InvokeHandler {
        abstract Object invoke(Method method, Object[] params) throws InvocationTargetException, IllegalAccessException;
    }

    // 代理类
    static class $Proxy0 implements Foo {

        private final InvokeHandler invokeHandler;

        private final Map<String, Method> cache = new HashMap<>();

        $Proxy0(InvokeHandler invokeHandler) {
            this.invokeHandler = invokeHandler;
        }

        @Override
        public Object foo() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
            // 1. 功能增强
            System.out.println("before");
            // 2. 调用目标
            Method foo = cache.getOrDefault("foo", null);
            if(foo == null) {
                foo = Foo.class.getMethod("foo");
                System.out.println(">>>>>> 新创建方法");
                cache.put("foo", foo);
            }

            return invokeHandler.invoke(foo, new Object[0]);
        }

        @Override
        public Object bar() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
            // 1. 功能增强
            System.out.println("before");
            // 2. 调用目标
            Method bar = cache.getOrDefault("bar", null);
            if(bar == null) {
                bar = Foo.class.getMethod("foo");
                System.out.println(">>>>>> 新创建方法");
                cache.put("bar", bar);
            }
            return invokeHandler.invoke(bar, new Object[0]);
        }
    }

    static class Target implements Foo {
        @Override
        public Integer foo() {
            System.out.println("target foo");
            return 1;
        }

        @Override
        public String  bar() {
            System.out.println("target bar");
            return "hello";
        }
    }


    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Foo f = new $Proxy0(new InvokeHandler() {
            @Override
            Object invoke(Method method, Object[] params) throws InvocationTargetException, IllegalAccessException {
                // 传入代理对象
                return method.invoke(new Target(), params);
            }

        });
        System.out.println(f.foo());
        System.out.println(f.bar());
        System.out.println(f.foo());
        System.out.println(f.bar());
    }
}

/**
before
>>>>>> 新创建方法
target foo
1
before
>>>>>> 新创建方法
target foo
1
before
target foo
1
before
target foo
1
**/

到此,代理方法只会被寻找一次。
JDK 动态代理生成的代理类是以字节码的形式存在的,并不存在所谓的 .java 文件,但也不是说就没办法看到生成的代理类信息了。不过可以使用 arthas反编译,看到字节码。
比如:

package com.example.proxy;

import java.io.IOException;
import java.lang.reflect.Proxy;

public class Jdk1 {
    interface Foo {
        void foo();
    }

    static final class Target implements Foo {
        @Override
        public void foo() {
            System.out.println("target foo");
        }
    }

    public static void main(String[] args) throws IOException {
        // 原始对象
        Target target = new Target();

        // 用来加载在运行期间动态生成的字节码
        ClassLoader classLoader = Jdk1.class.getClassLoader();
        Foo proxy = (Foo) Proxy.newProxyInstance(classLoader, new Class[]{Foo.class}, (p, method, params) -> {
            System.out.println("before...");
            // 目标.方法(参数) --> 方法.invoke(目标, 参数)
            Object result = method.invoke(target, params);
            System.out.println("after...");
            // 也返回目标方法执行的结果
            return result;
        });

        // 打印代理类的全限定类名
        System.out.println(proxy.getClass());

        proxy.foo();

        // 只要不在控制台上输入并回车,程序就不会终端
        System.in.read();
    }


}

打印的结果是:

class com.example.proxy.$Proxy0
before...
target foo
after...

arthas 反编译的结果是:

[arthas@60054]$ jad com.example.proxy.$Proxy0

ClassLoader:
+-jdk.internal.loader.ClassLoaders$AppClassLoader@251a69d7
  +-jdk.internal.loader.ClassLoaders$PlatformClassLoader@17747fbe

Location:

/*
 * Decompiled with CFR.
 *
 * Could not load the following classes:
 *  com.example.proxy.Jdk1$Foo
 */
package com.example.proxy;

import com.example.proxy.Jdk1;
import java.lang.invoke.MethodHandles;
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 Jdk1.Foo {
    private static final Method m0;
    private static final Method m1;
    private static final Method m2;
    private static final Method m3;

    private static MethodHandles.Lookup proxyClassLookup(MethodHandles.Lookup lookup) throws IllegalAccessException {
        if (lookup.lookupClass() == Proxy.class && lookup.hasFullPrivilegeAccess()) {
            return MethodHandles.lookup();
        }
        throw new IllegalAccessException(lookup.toString());
    }

    public $Proxy0(InvocationHandler invocationHandler) {
        super(invocationHandler);
    }

    static {
        try {
            m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
            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.example.proxy.Jdk1$Foo").getMethod("foo", new Class[0]);
            return;
        }
        catch (NoSuchMethodException noSuchMethodException) {
            throw new NoSuchMethodError(noSuchMethodException.getMessage());
        }
        catch (ClassNotFoundException classNotFoundException) {
            throw new NoClassDefFoundError(classNotFoundException.getMessage());
        }
    }

    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 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 int hashCode() {
        try {
            return (Integer)this.h.invoke(this, m0, null);
        }
        catch (Error | RuntimeException throwable) {
            throw throwable;
        }
        catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }

}

你可能感兴趣的:(Java探索者之路,jvm,java,开发语言)