Java Dynamic Proxy

栏目: Java · 发布时间: 5年前

内容简介:Proxy 是设计模式中的一种。当需要在已存在的 class 上添加或修改功能时,可以通过创建 proxy object 来实现通常 proxy object 和被代理对象拥有相同的方法,并且拥有被代理对象的引用,可以调用其方法代理模式

简介

Proxy 是 设计模式 中的一种。当需要在已存在的 class 上添加或修改功能时,可以通过创建 proxy object 来实现

通常 proxy object 和被代理对象拥有相同的方法,并且拥有被代理对象的引用,可以调用其方法

代理模式 应用场景 包括

  • 在方法执行前后打印和记录日志
  • 认证、参数检查
  • lazy instantiation (Hibernate, Mybatis)
  • AOP (transaction)
  • mocking

代理有两种实现方式

  • 静态代理:在编译时期,创建代理对象
  • 动态代理:在运行时期,动态创建

对于重复性工作,如打印日志,静态代理需要为每个 class 都创建 proxy class,过程繁琐和低效,而动态代理通过使用反射在运行时生成 bytecode 的方式来实现,更加方便和强大

过程

因为 JDK 自带的 Dynamic proxy 只能够代理 interfaces,因此被代理对象需要实现一个或多个接口,具体可参考 https://stackoverflow.com/a/10664208

先来看一些概念:

  • proxy interface proxy class 实现的接口
  • proxy class 运行时创建的代理 class,并实现一个或多个 proxy interface
  • proxy instance proxy class 的实例
  • InvocationHandler 每个 proxy instance 都有一个关联的 invocation handler,当调用 proxy 对象的方法时,会统一封装,并转发到 invoke() 方法

InvocationHandler 接口的定义如下

package java.lang.reflect;

public interface InvocationHandler {
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}

只定义了一个方法 invoke() ,参数含义如下

  • Object proxy 生成的代理对象
  • Method method 调用的方法,类型为 java.lang.reflect.Method
  • Object[] args 调用方法的参数,array of objects

简单来说就是,调用 proxy object 上的方法,最终都会转换成对关联 InvocationHandlerinvoke() 方法的调用

可以使用 java.lang.reflect.Proxy 的静态方法 newProxyInstance 来创建 Proxy object

public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
    ...
    }

参数说明

loader
interfaces
h

例子

使用动态代理打印方法的执行耗时

定义代理接口

public interface Foo {
    String doSomething();
}

实现接口

public class FooImpl implements Foo {
    @Override
    public String doSomething() {
        return "finished";
    }
}

定义 InvocationHandlertarget 为被代理对象的引用,在方法执行完后打印耗时

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class TimingInvocationHandler implements InvocationHandler {
    private Object target;

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

    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        long start = System.nanoTime();
        Object result = method.invoke(target, args);
        long elapsed = System.nanoTime() - start;

        System.out.println(String.format("Executing %s finished in %d ns",
                method.getName(),
                elapsed));

        return result;
    }
}

测试

import org.junit.Test;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

public class DynamicProxyTest {
    @Test
    public void test() {
        ClassLoader cl = DynamicProxyTest.class.getClassLoader();
        Class[] interfaces = new Class[]{Foo.class};
        FooImpl fooImpl = new FooImpl();
        InvocationHandler timingInvocationHandler = new TimingInvocationHandler(fooImpl);
        Foo foo = (Foo) Proxy.newProxyInstance(cl, interfaces, timingInvocationHandler);
        foo.doSomething();
    }
}

执行完会打印类似

Executing doSomething finished in 23148 ns

细节

生成 proxy class 的一些属性和细节

  • public, final, and not abstract.
  • 类名不确定,以 $Proxy 开头
  • 继承 java.lang.reflect.Proxy ,且 Proxy 实现了 java.io.Serializable 接口,因此 proxy instance 是可以序列化的
  • 按照 Proxy.newProxyInstance() 传入 interfaces 参数中的接口顺序来实现接口
  • 在 proxy class 上调用 getInterfacesgetMethodsgetMethod 方法,会返回实现的接口中定义的方法,顺序和创建时的参数保持一致
  • 当调用 proxy instance 同名、同 parameter signature 方法时, invoke() 方法的 Method 参数会是最早定义这个方法的 interface 的方法,无论实际调用的方法是什么
  • Foo 为实现的代理接口之一时, proxy instanceof Foo 返 true,并且可以转换 (Foo) proxy
  • Proxy.getInvocationHandler 静态方法会返回 proxy object 关联的 invocation handler

参考


以上所述就是小编给大家介绍的《Java Dynamic Proxy》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

PHP+MySQL八大动态Web应用实战

PHP+MySQL八大动态Web应用实战

Jono Bacom / 吴连河、李剑 / 电子工业出版社 / 2008-6 / 68.00元

本书详细介绍了利用PHP+MySQL开发常见类型Web应用程序的完整设计和编码技术,并对整体设计与关键代码给予了细致、深入的剖析。其内容注重实践,提供了翔实完整的实战代码;思路独树一帜,突破过多描述语言细节的窠臼;行文风趣幽默,轻松调侃中将项目的完整设计过程分析得一清二楚。书中的示例项目完整而实用,读者甚至无需任何改动即可在实际中加以运用。. 本书适合对PHP/MySQL有初步了解但缺乏完整......一起来看看 《PHP+MySQL八大动态Web应用实战》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具