@@ -1405,6 +1405,203 @@ java ShowMethods ShowMethods
14051405<!-- Dynamic Proxies -->
14061406## 动态代理
14071407
1408+ * 代理* 是基本的设计模式之一。它是你插入的对象,代替“真实”对象以提供其他或不同的操作---这些操作通常涉及到与“真实”对象的通信,因此代理通常充当中间对象。这是一个简单的示例,显示代理的结构:
1409+
1410+ ``` java
1411+ // typeinfo/SimpleProxyDemo.java
1412+
1413+ interface Interface {
1414+ void doSomething ();
1415+ void somethingElse (String arg );
1416+ }
1417+
1418+ class RealObject implements Interface {
1419+ @Override
1420+ public void doSomething () {
1421+ System . out. println(" doSomething" );
1422+ }
1423+ @Override
1424+ public void somethingElse (String arg ) {
1425+ System . out. println(" somethingElse " + arg);
1426+ }
1427+ }
1428+
1429+ class SimpleProxy implements Interface {
1430+ private Interface proxied;
1431+ SimpleProxy (Interface proxied ) {
1432+ this . proxied = proxied;
1433+ }
1434+ @Override
1435+ public void doSomething () {
1436+ System . out. println(" SimpleProxy doSomething" );
1437+ proxied. doSomething();
1438+ }
1439+ @Override
1440+ public void somethingElse (String arg ) {
1441+ System . out. println(
1442+ " SimpleProxy somethingElse " + arg);
1443+ proxied. somethingElse(arg);
1444+ }
1445+ }
1446+
1447+ class SimpleProxyDemo {
1448+ public static void consumer (Interface iface ) {
1449+ iface. doSomething();
1450+ iface. somethingElse(" bonobo" );
1451+ }
1452+ public static void main (String [] args ) {
1453+ consumer(new RealObject ());
1454+ consumer(new SimpleProxy (new RealObject ()));
1455+ }
1456+ }
1457+ /* Output:
1458+ doSomething
1459+ somethingElse bonobo
1460+ SimpleProxy doSomething
1461+ doSomething
1462+ SimpleProxy somethingElse bonobo
1463+ somethingElse bonobo
1464+ */
1465+ ```
1466+
1467+ 因为` consumer() ` 接受` Interface ` ,所以它不知道获得的是` RealObject ` 还是` SimpleProxy ` ,因为两者都实现了` Interface ` 。
1468+ 但是,在客户端和` RealObject ` 之间插入的` SimpleProxy ` 执行操作,然后在` RealObject ` 上调用相同的方法。
1469+
1470+ 当你希望将额外的操作与“真实对象”做分离时,代理可能会有所帮助,尤其是当你想要轻松地启用额外的操作时,反之亦然(设计模式就是封装变更---所以你必须改变一些东西以证明模式的合理性)。例如,如果你想跟踪对` RealObject ` 中方法的调用,或衡量此类调用的开销,该怎么办?这不是你要写入到程序中的代码,而且代理使你可以很轻松地添加或删除它。
1471+
1472+ Java的* 动态代理* 更进一步,不仅动态创建代理对象而且动态处理对代理方法的调用。在动态代理上进行的所有调用都被重定向到单个* 调用处理程序* ,该处理程序负责发现调用的内容并决定如何处理。这是` SimpleProxyDemo.java ` 使用动态代理重写的例子:
1473+
1474+ ``` java
1475+ // typeinfo/SimpleDynamicProxy.java
1476+ import java.lang.reflect.* ;
1477+
1478+ class DynamicProxyHandler implements InvocationHandler {
1479+ private Object proxied;
1480+ DynamicProxyHandler (Object proxied ) {
1481+ this . proxied = proxied;
1482+ }
1483+ @Override
1484+ public Object
1485+ invoke(Object proxy, Method method, Object [] args)
1486+ throws Throwable {
1487+ System . out. println(
1488+ " **** proxy: " + proxy. getClass() +
1489+ " , method: " + method + " , args: " + args);
1490+ if (args != null )
1491+ for (Object arg : args)
1492+ System . out. println(" " + arg);
1493+ return method. invoke(proxied, args);
1494+ }
1495+ }
1496+
1497+ class SimpleDynamicProxy {
1498+ public static void consumer (Interface iface ) {
1499+ iface. doSomething();
1500+ iface. somethingElse(" bonobo" );
1501+ }
1502+ public static void main (String [] args ) {
1503+ RealObject real = new RealObject ();
1504+ consumer(real);
1505+ // Insert a proxy and call again:
1506+ Interface proxy = (Interface )Proxy . newProxyInstance(
1507+ Interface . class. getClassLoader(),
1508+ new Class,
1509+ new DynamicProxyHandler (real));
1510+ consumer(proxy);
1511+ }
1512+ }
1513+ /* Output:
1514+ doSomething
1515+ somethingElse bonobo
1516+ **** proxy: class $Proxy0, method: public abstract void
1517+ Interface.doSomething(), args: null
1518+ doSomething
1519+ **** proxy: class $Proxy0, method: public abstract void
1520+ Interface.somethingElse(java.lang.String), args:
1521+ [Ljava.lang.Object;@6bc7c054
1522+ bonobo
1523+ somethingElse bonobo
1524+ */
1525+ ```
1526+
1527+ 可以通过调用静态方法`Proxy . newProxyInstance()`来创建动态代理,该方法需要一个类加载器(通常可以从已加载的对象中获取),希望代理实现的接口列表(不是类或抽象类),以及接口`InvocationHandler `的一个实现。动态代理会将所有调用重定向到调用处理程序,因此通常为调用处理程序的构造函数提供对“真实”对象的引用,以便一旦执行中介任务便可以转发请求。
1528+
1529+ `invoke()`方法被传递给代理对象,以防万一你必须区分请求的来源-- - 但是在很多情况下都无需关心。但是,在`invoke()`内的代理上调用方法时要小心,因为通过接口的调用是通过代理重定向的。
1530+
1531+ 通常执行代理操作,然后使用`Method . invoke()`传递必要的参数将请求转发给代理对象。这在一开始看起来是有限制的,好像你只能执行一般的操作。但是,可以过滤某些方法调用,同时传递其他方法调用:
1532+
1533+ ```java
1534+ // typeinfo/SelectingMethods.java
1535+ // Looking for particular methods in a dynamic proxy
1536+ import java.lang.reflect.*;
1537+
1538+ class MethodSelector implements InvocationHandler {
1539+ private Object proxied;
1540+ MethodSelector (Object proxied ) {
1541+ this . proxied = proxied;
1542+ }
1543+ @Override
1544+ public Object
1545+ invoke(Object proxy, Method method, Object [] args)
1546+ throws Throwable {
1547+ if (method. getName(). equals(" interesting" ))
1548+ System . out. println(
1549+ " Proxy detected the interesting method" );
1550+ return method. invoke(proxied, args);
1551+ }
1552+ }
1553+
1554+ interface SomeMethods {
1555+ void boring1 ();
1556+ void boring2 ();
1557+ void interesting (String arg );
1558+ void boring3 ();
1559+ }
1560+
1561+ class Implementation implements SomeMethods {
1562+ @Override
1563+ public void boring1 () {
1564+ System . out. println(" boring1" );
1565+ }
1566+ @Override
1567+ public void boring2 () {
1568+ System . out. println(" boring2" );
1569+ }
1570+ @Override
1571+ public void interesting (String arg ) {
1572+ System . out. println(" interesting " + arg);
1573+ }
1574+ @Override
1575+ public void boring3 () {
1576+ System . out. println(" boring3" );
1577+ }
1578+ }
1579+
1580+ class SelectingMethods {
1581+ public static void main (String [] args ) {
1582+ SomeMethods proxy =
1583+ (SomeMethods )Proxy . newProxyInstance(
1584+ SomeMethods . class. getClassLoader(),
1585+ new Class,
1586+ new MethodSelector (new Implementation ()));
1587+ proxy. boring1();
1588+ proxy. boring2();
1589+ proxy. interesting(" bonobo" );
1590+ proxy. boring3();
1591+ }
1592+ }
1593+ /* Output:
1594+ boring1
1595+ boring2
1596+ Proxy detected the interesting method
1597+ interesting bonobo
1598+ boring3
1599+ */
1600+ ```
1601+
1602+ 在这个示例里,我们只是在寻找方法名,但是你也可以寻找方法签名的其他方面,甚至可以搜索特定的参数值。
1603+
1604+ 动态代理不是你每天都会使用的工具,但是它可以很好地解决某些类型的问题。你可以在Erich Gamma 等人的* 设计模式* 中了解有关* 代理* 和其他设计模式的更多信息。 (Addison - Wesley ,1995 年),以及[设计模式](. / 25 - Patterns . md)一章。
14081605
14091606< ! -- Using Optional -- >
14101607## Optional 类
0 commit comments