`

jdk动态代理

 
阅读更多

 

简介

jdk动态代理用于在运行时生成实现多个接口的动态代理类,关键的类有两个

Proxy:提供多个静态方法用于创建动态代理类和动态代理对象,同时也是所有此种方式生成的动态代理类的父类

InvocationHandler:该接口只有一个方法如下,每个动态代理对象都有一个关联的InvocationHandler实例对象,当一个动态代理对象的方法被调用时,实际上是被分配到了InvocationHandler实例对象的invoke方法

 

public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable

 

 

例子

Proxy中有两种代码方式生成动态代理对象(假设代理的接口为Foo):

 

     //生成InvocationHandler对象
     InvocationHandler handler = new MyInvocationHandler(...);
    //方法1 生成代理类 再获得代理类的构造方法然后newInstance
      Class<?> proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(), Foo.class);
      Foo f = (Foo) proxyClass.getConstructor(InvocationHandler.class).
                      newInstance(handler);
    //方法2 在方法里一步解决生成代理对象
     Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
                                          new Class<?>[] { Foo.class },
                                          handler);

 这里以第二种为例子

//接口Person
public interface Person {
    public void say(String name);
}
//实现类Chinese
public class Chinese implements  Person {
    @Override
    public void say(String name) {
        System.out.println(name + "你好");
    }
}
//测试类
public class Test {
    public static void main(String[] args) throws Exception{
      //设置系统参数保存生成的代理类到文件中,可以到项目根目录下com/sun/proxy目录中找到代理类class文件
        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
        final Person person = new Chinese();
        InvocationHandler handler = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("test");
                return method.invoke(person, args);
            }
        };

        Person proxy = (Person) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
                new Class[]{Person.class},handler);

        proxy.say("justin");
    }
}

结果:test
      justin你好

 

 代码分析

 为什么这样写,以及为什么能得到这样的结果可以通过看代理类class文件得到答案

 

//代理类实现代理接口继承Proxy类
public final class $Proxy0 extends Proxy implements Person {
   //从后面的静态代码块可以看出这几个Method属性就是代理接口(以及Object类)中方法的反射对象
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m0;
  //参数为InvocationHandler的构造函数 用于生成代理对象,父类Proxy中该方法作用就是将var1赋值给属性InvocationHandler
    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }
  //重写代理接口和Object方法,同时都改成final方法,方法内容都一致:
以生成的代理类、接口或Object类的方法反射对象、方法调用参数为参数调用父类Proxy中InvocationHandler属性h(也就是构造函数传入的var1)的invoke方法
上面的测试类Test中handler对象的invoke方法,第一句system.out.println("test")相当于功能增强,第二句return method.invoke(person,args);是实际上执行方法的语句
这里person是方法的实际调用者,代理类传过来的proxy一般不用。
对比直接用person调用差别只是功能增强的打印语句那一块
    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, 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 void say(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 int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }
    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("com.test.proxy.Person").getMethod("say", Class.forName("java.lang.String"));
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

生成代理类分析

Proxy的newProxyInstance方法内容如下:

public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
       //保证参数h不为空
        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对象 这里会缓存到一个WeakCache中如果用相同的ClassLoader和接口生成过代理类那直接从这里取,如果没有则用二进制拼接出class内容,在加载到内存中
         */
        Class<?> cl = getProxyClass0(loader, intfs);

        /*
         * Invoke its constructor with the designated invocation handler.
         */
        try {
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }
         //这里的constructorParams是{InvocationHandler.class} 获得参数类型为InvocationHandler的构造方法
            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
            }
           //返回方法代理类实例
            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);
        }
    }

 

 

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics