JDK动态代理解析

要了解JDK的动态代理,我们首先要知道为什么需要动态代理,而不是普通的静态代理

先看一个简单的静态代理

  • 被代理的接口
public interface HelloWorld {

    void sayHello(String name);
}
  • 被代理实现类
public class HelloWorldImpl implements HelloWorld {

    public void sayHello(String name) {
        System.out.println("hello nice world: " + name);
    }
}
  • 代理类 & 测试类
**
 * @author wangjn
 * @description 普通代理
 * @date Created on 2017/12/26.
 */
public class HelloWorldProxy {
    private HelloWorld helloWorld;

    HelloWorldProxy (HelloWorld helloWorld) {
        this.helloWorld = helloWorld;
    }

    void sayHello() {
        System.out.println("Before sample proxy---->");
        helloWorld.sayHello("wangjn");
        System.out.println("After sample proxy---->");
    }

    public static void main(String[] args) {
        HelloWorld helloWorld = new HelloWorldImpl();
        HelloWorldProxy proxy = new HelloWorldProxy(helloWorld);
        proxy.sayHello();
    }
}

执行测试类,输出:

Before sample proxy----> hello nice world: wangjn After sample proxy---->

可以看到,这是一个很简单的代理模式,我们写一个这样的类也很快。可问题是,如果我们有十几二十个类似HelloWorld这样的业务逻辑需要代理,我们就需要写十几二十个代理类,这是无法避免的且无法忍受的 由此引申出动态代理

动态代理的实现

实现一个动态代理也非常简单

  • 动态代理类 实现 InvocationHandler 接口
public class HelloWorldInvocationHandler implements InvocationHandler{
    private Object target;

    public HelloWorldInvocationHandler(Object target) {
        this.target = target;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Before invocation---->");
        Object retVal = method.invoke(target, args);
        System.out.println("<----After invocation");
        return retVal;
    }
}
  • 测试类
public class JDKDynamicProxyTest {

    public static void main(String[] args) {
        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");

        HelloWorldInvocationHandler handler = new HelloWorldInvocationHandler(new HelloWorldImpl());
        HelloWorld proxy = (HelloWorld) Proxy.newProxyInstance(
                JDKDynamicProxyTest.class.getClassLoader(),
                new Class[]{HelloWorld.class},
                handler);
        proxy.sayHello("wangjn");
    }
}

运行结果:

Before invocation----> hello nice world: wangjn <----After invocation

主要实现逻辑在 Proxy.newProxyInstance中

  • Proxy.newProxyInstance 方法源码
public static Object newProxyInstance(ClassLoader loader,
                                      Class[] interfaces,
                                      InvocationHandler h)
    throws IllegalArgumentException
{
    Objects.requireNonNull(h);

    final Class[] intfs = interfaces.clone();
    final SecurityManager sm = System.getSecurityManager();
    if (sm != null) {
        checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
    }

    /*
     * Look up or generate the designated proxy class.
     * 生成Class 文件的重要代码,这里不深究是如何生成的
     */
    Class cl = getProxyClass0(loader, intfs);

    /*
     * Invoke its constructor with the designated invocation handler.
     */
    try {
        if (sm != null) {
            checkNewProxyPermission(Reflection.getCallerClass(), cl);
        }
            // 获取生成的class的构造方法 参数类型为 InvocationHandler.class
        final Constructor cons = cl.getConstructor(constructorParams);
        final InvocationHandler ih = h;
        if (!Modifier.isPublic(cl.getModifiers())) {
            AccessController.doPrivileged(new PrivilegedAction() {
                public Void run() {
                    cons.setAccessible(true);
                    return null;
                }
            });
        }
        // 调用参数为 InvocationHandler h 的构造方法创建实例
        return cons.newInstance(new Object[]{h});
    } catch (IllegalAccessException|InstantiationException e) {
        throw new InternalError(e.toString(), e);
    } catch (InvocationTargetException e) {
        Throwable t = e.getCause();
        if (t instanceof RuntimeException) {
            throw (RuntimeException) t;
        } else {
            throw new InternalError(t.toString(), t);
        }
    } catch (NoSuchMethodException e) {
        throw new InternalError(e.toString(), e);
    }
}

看到这里,我们肯定想要看一下 Class cl = getProxyClass0(loader, intfs) 生成的class文件长什么样吧..

那我们现在就来看一下 这个动态生成的class长什么样

  • $Proxy0 反编译查看
public final class $Proxy0 extends Proxy implements HelloWorld {
    private static Method m1;
    private static Method m3;
    private static Method m2;
    private static Method m0;

    public $Proxy0(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 sayHello(String var1) throws  {
        try {
            super.h.invoke(this, m3, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    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.taromilkbread.bird.HelloWorld").getMethod("sayHello", new Class[]{Class.forName("java.lang.String")});
            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());
        }
    }
}

看了动态生成的class,疑惑瞬间解了一大半

  • $Proxy0 实现了HelloWorld接口,且继承了Proxy 类。
  • 并且构造函数的参数就是 InvocationHandler h(我们自己实现的HelloWorldInvocationHandler代理类),跟Proxy中的newProxyInstance方法终于对接上了!
  • 每个 Method 也都在静态块里进行了初始化..

不过JDK动态代理有致命弱点,因为java不允许多继承,而动态生成的class 却继承了Proxy类! 只能是实现了接口的类才可以被代理

不过好在之后已经有了解决方案.

你可能感兴趣的:(JDK动态代理解析)