Java动态代理
在学习《Java编程思想》的时候看到了动态代理,觉得很有意思,现在来做一下总结。
一、代理模式的定义
为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
二、优点
三、模式结构
一个是真正的你要访问的对象(目标类),一个是代理对象,真正对象与代理对象实现同一个接口,先访问代理类再访问真正要访问的对象。
四、UML示意图
我们来看一个普通代理实现的例子:
1 //客户端接口
2 interface Interface {
3
4 void doSomething();
5
6 void somethingElse(String arg);
7 }
8
9 //客户端实现类,就是执行业务逻辑的类
10 class RealObject implements Interface {
11
12 @Override
13 public void doSomething() {
14 // TODO Auto-generated method stub
15 System.out.println("doSomething");
16 }
17
18 @Override
19 public void somethingElse(String arg) {
20 // TODO Auto-generated method stub
21 System.out.println("somethingElse" + arg);
22 }
23
24 }
25
26 //代理类
27 class SimpleProxy implements Interface {
28
29 private Interface proxied;
30
31 public SimpleProxy(Interface proxied) {
32 // TODO Auto-generated constructor stub
33 this.proxied = proxied;
34 }
35
36 @Override
37 public void doSomething() {
38 // TODO Auto-generated method stub
39 System.out.println("SimpleProxy doSomething");
40 proxied.doSomething();
41 }
42
43 @Override
44 public void somethingElse(String arg) {
45 // TODO Auto-generated method stub
46 System.out.println("SimpleProxy somethingElse "+arg);
47 proxied.somethingElse(arg);
48 }
49
50 }
51
52 public class SimpleProxyDemo{
53
54 public static void consumer(Interface iface){
55 iface.doSomething();
56 iface.somethingElse("hello world");
57 }
58
59 public static void main(String[] args){
60 consumer(new RealObject());
61 System.out.println("/*****************************/");
62 consumer(new SimpleProxy(new RealObject()));
63 }
64 }
运行结果如下:
1 doSomething
2 somethingElsehello world
3 /*****************************/
4 SimpleProxy doSomething
5 doSomething
6 SimpleProxy somethingElse hello world
7 somethingElsehello world
五、Java动态代理
Java的动态代理比代理的思想更向前迈进了一步,因为它可以动态地创建代理并动态地处理对所代理方法的调用。在动态代理上所做的所有调用都会被重定向到单一的调用处理器上,它的工作揭示调用的类型并确定相应的对策。
接下来我们来看一下Java动态代理的例子:
1 interface Interface {
2
3 void doSomething();
4
5 void somethingElse(String arg);
6 }
7
8 class RealObject implements Interface {
9
10 @Override
11 public void doSomething() {
12 // TODO Auto-generated method stub
13 System.out.println("doSomething");
14 }
15
16 @Override
17 public void somethingElse(String arg) {
18 // TODO Auto-generated method stub
19 System.out.println("somethingElse" + arg);
20 }
21
22 }
23
24 //动态代理类
25 class DynamicProxyHandler implements InvocationHandler{
26
27 private Object proxied;
28
29 public DynamicProxyHandler(Object proxied) {
30 // TODO Auto-generated constructor stub
31 this.proxied = proxied;
32 }
33
34 @Override
35 public Object invoke(Object proxy, Method method, Object[] args)
36 throws Throwable {
37 // TODO Auto-generated method stub
38 System.out.println("****proxy: " + proxy.getClass()+
39 ", method: "+method+ ", args: "+ args);
40
41 if(args != null){
42 for (Object arg : args) {
43 System.out.println(" "+ arg);
44 }
45 }
46
47 return method.invoke(proxied, args);
48 }
49 }
50
51 class SimpleDynamicProxy{
52
53 public static void consumer(Interface iface){
54 iface.doSomething();
55 iface.somethingElse("hello world");
56 }
57
58 public static void main(String[] args){
59 RealObject real = new RealObject();
60 consumer(real);
61
62 System.out.println("/*******************************/");
63
64 Interface proxy = (Interface)Proxy.newProxyInstance(
65 Interface.class.getClassLoader(),
66 new Class[]{Interface.class},
67 new DynamicProxyHandler(real));
68
69 consumer(proxy);
70
71 }
72
73 }
运行结果如下:
1 doSomething
2 somethingElsehello world
3 /*******************************/
4 ****proxy: class com.sun.proxy.$Proxy0, method: public abstract void Interface.doSomething(), args: null
5 doSomething
6 ****proxy: class com.sun.proxy.$Proxy0, method: public abstract void Interface.somethingElse(java.lang.String), args: [Ljava.lang.Object;@756095fc
7 hello world
8 somethingElsehello world
通过调用静态方法Proxy.newProxyInstance()可以创建动态代理。这个方法需要得到一个类加载器(你通常可以从已经被加载的对象中获取其类加载器,然后传递给它),一个你希望该代理实现的接口列表(不是类或者抽象类),以及InvocationHandler接口的一个实现。动态代理可以将所有调用重定向到调用处理器,因此通常会向调用处理器的构造器传递一个“实际”对象的引用,从而使得调用处理器执行其中介任务时,可以将请求转发。
invoke()方法传递进来了代理对象,以防你需要区分请求的来源,但是在许多情况下,你并不关心这一点。然而,在invoke()内部,在代理上调用方法时需要格外小心,因为接口的调用将被重定向为对代理对象的调用。
通常,你会执行被代理的操作,然后使用Method.invoke()将请求转发给 被代理对象,并传入必需的参数。这初看起来可能有些受限,就像你只能执行泛化操作一样。但是,你可以通过传递其他的参数,来过滤某些方法的调用。