Java的dynamic proxy(动态代理)的使用学习(一)

Java提供了「动态代理」机制,可以通过InvocationHandler把所需的class给封装一下,然后封装了Class后的proxy可以表现为原Class的类型。这篇文章来看一下具体的使用方法。首先下面是这个InvocationHandler的接口:

这个接口提供一个invoke()方法,并且接收上面给出的几个参数。根据这个接口,我们来实现一个BasicProxyHandler,类图如下:

可以看到这个class实现了InvocationHandler的接口。此外,这个proxy class会被用来代理Foo这个接口,而实际实现Foo接口的是FooImpl

需要注意的是,在InvocationHandler里面有一个original的object,这个会被用来保存实际的FooImpl实例。

接下来看一下invoke()方法的代码:

下面是逻辑图:

可以看到这里面的逻辑主要就是使用original调用传入的method,并且把传入的args传给method

总结来讲,就是通过反射的方法,来调用original的实际方法。但是在这个逻辑上下,可以看到加入了两行System.out.println()的代码。因此当我们使用proxy的时候,等于在原始object的方法调用前后加了两行日志的输出。

接下来可以看看这个proxy的具体使用。看一下main()方法里面的实际代码:

可以看到我们创建了一个FooImpl的实例,然后针对这个实例创建了一个Proxy。注意这个Proxy对应Foo.class,并且使用BasicProxyHandler作为代理的实际处理class。

最后生成的这个proxy成为了Foo类型的一个class,但实际上它是BasicProxyHandler代理的,并且会使用代理类里面的invoke()方法来进行实际的逻辑处理。

接下来我们运行一下main()方法,看一下执行效果:

可以看到,除了FooImplecho()方法输出的Hello, world!以外,我们还看到上下两行额外输出的日志,这个是invoke()方法里面我们添加的日志。

此外,在最后一行日志可以看到,这个类型为Fooproxy,它的实际class是$Proxy0,因此可以看到动态代理的class是runtime生成的,这是JVM虚拟机提供给我们的方便之处。

这篇文章使用的代码在这里:

有兴趣可以拿下来运行试试看。

Powered by Jekyll and Theme by solid