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()
方法,看一下执行效果:
可以看到,除了FooImpl
的echo()
方法输出的Hello, world!
以外,我们还看到上下两行额外输出的日志,这个是invoke()
方法里面我们添加的日志。
此外,在最后一行日志可以看到,这个类型为Foo
的proxy
,它的实际class是$Proxy0
,因此可以看到动态代理的class是runtime生成的,这是JVM虚拟机提供给我们的方便之处。
这篇文章使用的代码在这里:
有兴趣可以拿下来运行试试看。