mirror of
https://github.com/LingCoder/OnJava8.git
synced 2026-08-24 15:03:29 +08:00
Signed-off-by: Trency <trency92@gmail.com>
Fix issue #28: 翻译类型信息部分 动态代理小节
This commit is contained in:
@@ -1405,6 +1405,203 @@ java ShowMethods ShowMethods
|
||||
<!-- Dynamic Proxies -->
|
||||
## 动态代理
|
||||
|
||||
*代理*是基本的设计模式之一。它是你插入的对象,代替“真实”对象以提供其他或不同的操作---这些操作通常涉及到与“真实”对象的通信,因此代理通常充当中间对象。这是一个简单的示例,显示代理的结构:
|
||||
|
||||
```java
|
||||
// typeinfo/SimpleProxyDemo.java
|
||||
|
||||
interface Interface {
|
||||
void doSomething();
|
||||
void somethingElse(String arg);
|
||||
}
|
||||
|
||||
class RealObject implements Interface {
|
||||
@Override
|
||||
public void doSomething() {
|
||||
System.out.println("doSomething");
|
||||
}
|
||||
@Override
|
||||
public void somethingElse(String arg) {
|
||||
System.out.println("somethingElse " + arg);
|
||||
}
|
||||
}
|
||||
|
||||
class SimpleProxy implements Interface {
|
||||
private Interface proxied;
|
||||
SimpleProxy(Interface proxied) {
|
||||
this.proxied = proxied;
|
||||
}
|
||||
@Override
|
||||
public void doSomething() {
|
||||
System.out.println("SimpleProxy doSomething");
|
||||
proxied.doSomething();
|
||||
}
|
||||
@Override
|
||||
public void somethingElse(String arg) {
|
||||
System.out.println(
|
||||
"SimpleProxy somethingElse " + arg);
|
||||
proxied.somethingElse(arg);
|
||||
}
|
||||
}
|
||||
|
||||
class SimpleProxyDemo {
|
||||
public static void consumer(Interface iface) {
|
||||
iface.doSomething();
|
||||
iface.somethingElse("bonobo");
|
||||
}
|
||||
public static void main(String[] args) {
|
||||
consumer(new RealObject());
|
||||
consumer(new SimpleProxy(new RealObject()));
|
||||
}
|
||||
}
|
||||
/* Output:
|
||||
doSomething
|
||||
somethingElse bonobo
|
||||
SimpleProxy doSomething
|
||||
doSomething
|
||||
SimpleProxy somethingElse bonobo
|
||||
somethingElse bonobo
|
||||
*/
|
||||
```
|
||||
|
||||
因为`consumer()`接受`Interface`,所以它不知道获得的是`RealObject`还是`SimpleProxy`,因为两者都实现了`Interface`。
|
||||
但是,在客户端和`RealObject`之间插入的`SimpleProxy`执行操作,然后在`RealObject`上调用相同的方法。
|
||||
|
||||
当你希望将额外的操作与“真实对象”做分离时,代理可能会有所帮助,尤其是当你想要轻松地启用额外的操作时,反之亦然(设计模式就是封装变更---所以你必须改变一些东西以证明模式的合理性)。例如,如果你想跟踪对`RealObject`中方法的调用,或衡量此类调用的开销,该怎么办?这不是你要写入到程序中的代码,而且代理使你可以很轻松地添加或删除它。
|
||||
|
||||
Java的*动态代理*更进一步,不仅动态创建代理对象而且动态处理对代理方法的调用。在动态代理上进行的所有调用都被重定向到单个*调用处理程序*,该处理程序负责发现调用的内容并决定如何处理。这是`SimpleProxyDemo.java`使用动态代理重写的例子:
|
||||
|
||||
```java
|
||||
// typeinfo/SimpleDynamicProxy.java
|
||||
import java.lang.reflect.*;
|
||||
|
||||
class DynamicProxyHandler implements InvocationHandler {
|
||||
private Object proxied;
|
||||
DynamicProxyHandler(Object proxied) {
|
||||
this.proxied = proxied;
|
||||
}
|
||||
@Override
|
||||
public Object
|
||||
invoke(Object proxy, Method method, Object[] args)
|
||||
throws Throwable {
|
||||
System.out.println(
|
||||
"**** proxy: " + proxy.getClass() +
|
||||
", method: " + method + ", args: " + args);
|
||||
if(args != null)
|
||||
for(Object arg : args)
|
||||
System.out.println(" " + arg);
|
||||
return method.invoke(proxied, args);
|
||||
}
|
||||
}
|
||||
|
||||
class SimpleDynamicProxy {
|
||||
public static void consumer(Interface iface) {
|
||||
iface.doSomething();
|
||||
iface.somethingElse("bonobo");
|
||||
}
|
||||
public static void main(String[] args) {
|
||||
RealObject real = new RealObject();
|
||||
consumer(real);
|
||||
// Insert a proxy and call again:
|
||||
Interface proxy = (Interface)Proxy.newProxyInstance(
|
||||
Interface.class.getClassLoader(),
|
||||
new Class,
|
||||
new DynamicProxyHandler(real));
|
||||
consumer(proxy);
|
||||
}
|
||||
}
|
||||
/* Output:
|
||||
doSomething
|
||||
somethingElse bonobo
|
||||
**** proxy: class $Proxy0, method: public abstract void
|
||||
Interface.doSomething(), args: null
|
||||
doSomething
|
||||
**** proxy: class $Proxy0, method: public abstract void
|
||||
Interface.somethingElse(java.lang.String), args:
|
||||
[Ljava.lang.Object;@6bc7c054
|
||||
bonobo
|
||||
somethingElse bonobo
|
||||
*/
|
||||
```
|
||||
|
||||
可以通过调用静态方法`Proxy.newProxyInstance()`来创建动态代理,该方法需要一个类加载器(通常可以从已加载的对象中获取),希望代理实现的接口列表(不是类或抽象类),以及接口`InvocationHandler`的一个实现。动态代理会将所有调用重定向到调用处理程序,因此通常为调用处理程序的构造函数提供对“真实”对象的引用,以便一旦执行中介任务便可以转发请求。
|
||||
|
||||
`invoke()`方法被传递给代理对象,以防万一你必须区分请求的来源---但是在很多情况下都无需关心。但是,在`invoke()`内的代理上调用方法时要小心,因为通过接口的调用是通过代理重定向的。
|
||||
|
||||
通常执行代理操作,然后使用`Method.invoke()`传递必要的参数将请求转发给代理对象。这在一开始看起来是有限制的,好像你只能执行一般的操作。但是,可以过滤某些方法调用,同时传递其他方法调用:
|
||||
|
||||
```java
|
||||
// typeinfo/SelectingMethods.java
|
||||
// Looking for particular methods in a dynamic proxy
|
||||
import java.lang.reflect.*;
|
||||
|
||||
class MethodSelector implements InvocationHandler {
|
||||
private Object proxied;
|
||||
MethodSelector(Object proxied) {
|
||||
this.proxied = proxied;
|
||||
}
|
||||
@Override
|
||||
public Object
|
||||
invoke(Object proxy, Method method, Object[] args)
|
||||
throws Throwable {
|
||||
if(method.getName().equals("interesting"))
|
||||
System.out.println(
|
||||
"Proxy detected the interesting method");
|
||||
return method.invoke(proxied, args);
|
||||
}
|
||||
}
|
||||
|
||||
interface SomeMethods {
|
||||
void boring1();
|
||||
void boring2();
|
||||
void interesting(String arg);
|
||||
void boring3();
|
||||
}
|
||||
|
||||
class Implementation implements SomeMethods {
|
||||
@Override
|
||||
public void boring1() {
|
||||
System.out.println("boring1");
|
||||
}
|
||||
@Override
|
||||
public void boring2() {
|
||||
System.out.println("boring2");
|
||||
}
|
||||
@Override
|
||||
public void interesting(String arg) {
|
||||
System.out.println("interesting " + arg);
|
||||
}
|
||||
@Override
|
||||
public void boring3() {
|
||||
System.out.println("boring3");
|
||||
}
|
||||
}
|
||||
|
||||
class SelectingMethods {
|
||||
public static void main(String[] args) {
|
||||
SomeMethods proxy =
|
||||
(SomeMethods)Proxy.newProxyInstance(
|
||||
SomeMethods.class.getClassLoader(),
|
||||
new Class,
|
||||
new MethodSelector(new Implementation()));
|
||||
proxy.boring1();
|
||||
proxy.boring2();
|
||||
proxy.interesting("bonobo");
|
||||
proxy.boring3();
|
||||
}
|
||||
}
|
||||
/* Output:
|
||||
boring1
|
||||
boring2
|
||||
Proxy detected the interesting method
|
||||
interesting bonobo
|
||||
boring3
|
||||
*/
|
||||
```
|
||||
|
||||
在这个示例里,我们只是在寻找方法名,但是你也可以寻找方法签名的其他方面,甚至可以搜索特定的参数值。
|
||||
|
||||
动态代理不是你每天都会使用的工具,但是它可以很好地解决某些类型的问题。你可以在Erich Gamma等人的*设计模式*中了解有关*代理*和其他设计模式的更多信息。 (Addison-Wesley,1995年),以及[设计模式](./25-Patterns.md)一章。
|
||||
|
||||
<!-- Using Optional -->
|
||||
## Optional类
|
||||
|
||||
Reference in New Issue
Block a user