@@ -1405,6 +1405,203 @@ java ShowMethods ShowMethods
1405
1405
<!-- Dynamic Proxies -->
1406
1406
## 动态代理
1407
1407
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)一章。
1408
1605
1409
1606
< ! -- Using Optional -- >
1410
1607
## Optional 类
0 commit comments