Proxy

作者: 童伯虎 | 来源:发表于2019-01-15 10:54 被阅读0次

1. 举例

  • 接口
public interface Hello {

    void hello(String name);
}
  • 实现类
public class HelloImpl implements Hello {

    @Override
    public void hello(String name) {
        System.out.println("Hello, " + name);
    }
}
  • 代理类:拦截方法,统计执行时间
public class HelloProxy implements InvocationHandler {

    private HelloImpl impl;

    public HelloProxy(HelloImpl impl) {
        this.impl = impl;
    }

    public Hello create() {
        return (Hello) Proxy.newProxyInstance(Hello.class.getClassLoader(), 
            new Class<?>[]{Hello.class}, this);
    }

    /**
     * 方法拦截
     * @param proxy   真正的代理类实例
     * @param method 拦截的接口方法
     * @param args   方法调用参数
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        long startTime = System.nanoTime();
        
        System.out.println("执行" + proxy.getClass().getName() + "." + method.getName());
        // 反射调用代理接口实现类方法
        Object result = method.invoke(impl, args);
        
        long endTime = System.nanoTime();
        System.out.println("耗时" + (endTime - startTime) + "纳秒");
        
        return result;
    }
}
  • 测试
Hello hello = new HelloProxy(new HelloImpl()).create();
hello.hello("World");

执行结果:

执行com.sun.proxy.$Proxy0.hello
Hello, World
耗时371467纳秒

2. 代理类

  • 获取代理类Class文件
byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{ Hello.class });
FileOutputStream fos = null;
try {
    fos = new FileOutputStream("D:/Temp/$Proxy0.class");
    fos.write(classFile);
    fos.flush();
} catch (Exception e) {
    e.printStackTrace();
} finally {
    if (fos != null) {
        try {
            fos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
  • 生成的代理类
// 继承Proxy,实现接口
public final class $Proxy0 extends Proxy implements Hello {
    
    private static Method objectHashCode;
    private static Method objectEquals;
    private static Method objectToString;
    
    private static Method proxyHello;
    
    static {
        try {
            // 获取所有要重载的方法

            objectHashCode = Class.forName("java.lang.Object").getMethod("hashCode");
            objectEquals = Class.forName("java.lang.Object").getMethod("equals", 
                Class.forName("java.lang.Object"));
            objectToString = Class.forName("java.lang.Object").getMethod("toString");
            
            proxyHello = Class.forName("Hello").getMethod("hello", 
                Class.forName("java.lang.String"));
            
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
            
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }

    // 代理构造方法,传入InvocationHandler实例
    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }
    
    // 重载Object.hashCode()
    public final int hashCode() throws  {
        try {
            // 转发到InvocationHandler.invoke
            return (Integer)super.h.invoke(this, objectHashCode, (Object[])null);
            
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    // 重载Object.equals()
    public final boolean equals(Object var1) throws  {
        try {
            // 转发到InvocationHandler.invoke
            return (Boolean)super.h.invoke(this, objectEquals, new Object[]{var1});
            
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    // 重载Object.toString()
    public final String toString() throws  {
        try {
            // 转发到InvocationHandler.invoke
            return (String)super.h.invoke(this, objectToString, (Object[])null);
            
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    // 重载接口方法
    public final void hello(String var1) throws  {
        try {
            // 转发到InvocationHandler.invoke
            super.h.invoke(this, proxyHello, new Object[]{var1});
            
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }
}

3. Proxy

Proxy提供静态方法创建动态代理类和实例,亦是所有动态代理类的基类。

为接口Foo创建代理:
InvocationHandler handler = new MyInvocationHandler(...);
Class<?> proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(), Foo.class);
Foo f = (Foo) proxyClass.getConstructor(InvocationHandler.class).newInstance(handler);
或:
Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(), new Class<?>[]{ Foo.class }, handler);

代理类运行时生成,实现代理接口,将所有接口方法的调用转发到InvocationHandler.invoke(Object proxy, Method method, Object[] args)。
invoke()可以通过反射调用代理接口真正实现类的相应方法,并在反射调用前后执行其他操作如计时,以完成拦截目的。

public class Proxy {

    // 生成代理类实例
    public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) {
        // 代理类要实现的接口
        final Class<?>[] intfs = interfaces.clone();
        // 生成代理类
        Class<?> cl = getProxyClass0(loader, intfs);
        // 代理类构造方法
        Constructor<?> cons = cl.getConstructor(new Class<?>[]{ InvocationHandler.class });
        // 生成代理类实例
        return cons.newInstance(new Object[]{h});
    }

    // 代理类包含InvocationHandler实例
    protected InvocationHandler h;
    // 代理类构造方法调用
    protected Proxy(InvocationHandler h) {
        this.h = h;
    }

    // 代理类缓存
    private static final WeakCache<ClassLoader, Class<?>[], Class<?>> proxyClassCache = 
        new WeakCache<>(new KeyFactory(), new ProxyClassFactory());

    private static Class<?> getProxyClass0(ClassLoader loader, Class<?>... interfaces) {
        // 通过ProxyClassFactory生成代理类,并放入缓存
        return proxyClassCache.get(loader, interfaces);
    }

    // 代理类工厂:生成代理类字节代码、定义代理类
    private static final class ProxyClassFactory
        implements BiFunction<ClassLoader, Class<?>[], Class<?>> {
        
        // 代理类类名前缀
        private static final String proxyClassNamePrefix = "$Proxy";

        // 代理类编号,以生成唯一类名
        private static final AtomicLong nextUniqueNumber = new AtomicLong();

        /**
         * @param loader 代理类加载器
         * @param interfaces 代理类要实现的接口
         */
        @Override
        public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {

            // 验证接口
            Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
            for (Class<?> intf : interfaces) {
                // 类加载器解析的接口类名与指定的相同
                Class<?> interfaceClass = null;
                try {
                    interfaceClass = Class.forName(intf.getName(), false, loader);
                } catch (ClassNotFoundException e) {
                }
                if (interfaceClass != intf) {
                    throw new IllegalArgumentException(intf + " is not visible from class loader");
                }
                // 是接口
                if (!interfaceClass.isInterface()) {
                    throw new IllegalArgumentException(interfaceClass.getName() + " is not an interface");
                }
                // 接口不重复
                if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
                    throw new IllegalArgumentException("repeated interface: " + interfaceClass.getName());
                }
            }

            // 代理类所在包
            String proxyPkg = null;
            
            // 代理类默认为public final
            int accessFlags = Modifier.PUBLIC | Modifier.FINAL;

            // 如果代理接口有非public,则使代理类与接口同包
            for (Class<?> intf : interfaces) {
                int flags = intf.getModifiers();
                if (!Modifier.isPublic(flags)) {
                    accessFlags = Modifier.FINAL;
                    String name = intf.getName();
                    int n = name.lastIndexOf('.');
                    String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
                    if (proxyPkg == null) {
                        proxyPkg = pkg;
                    } else if (!pkg.equals(proxyPkg)) {
                        throw new IllegalArgumentException("non-public interfaces from different packages");
                    }
                }
            }

            // 代理类所在包默认为com.sun.proxy
            if (proxyPkg == null) {
                proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
            }
            
            long num = nextUniqueNumber.getAndIncrement();
            // 代理类完全限定名
            String proxyName = proxyPkg + proxyClassNamePrefix + num;

            // 生成代理类字节代码(请参看第2节)
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags);
            try {
                // 类加载器定义代理类
                return defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length);
            } catch (ClassFormatError e) {
                throw new IllegalArgumentException(e.toString());
            }
        }
    }

}

相关文章

网友评论

    本文标题:Proxy

    本文链接:https://www.haomeiwen.com/subject/tivsdqtx.html