查看: 26|回复: 1

java动态代理、Proxy与InvocationHandler

[复制链接]
新浪微博达人勋 sj_ 实名认证
论坛徽章:
3
机器学习徽章
日期:2018-03-29 16:05:00Git徽章
日期:2018-06-07 16:21:59股票徽章
日期:2018-06-29 11:14:50
发表于 2018-7-8 23:23 | 显示全部楼层 |阅读模式

编程

1、代理的基本构成

  抽象角色:声明真实对象和代理对象的共同接口,这样可在任何使用真实对象的地方都可以使用代理对象。

  代理角色:代理对象内部含有真实对象的引用,从而可以在任何时候操作真实对象。代理对象提供一个与真实对象相同的接口,以便可以在任何时候替代真实对象。代理对象通常在客户端调用传递给真实对象之前或之后,执行某个操作,而不是单纯地将调用传递给真实对象,同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。

  真实角色:即为代理对象所代表的目标对象,代理角色所代表的真实对象,是我们最终要引用的对象。

  下图有三种角色:Subject抽象角色、RealSubject真实角色、Proxy代理角色。其中:Subject角色负责定义RealSubject和Proxy角色应该实现的接口;RealSubject角色用来真正完成业务服务功能;Proxy角色负责将自身的request请求,调用RealSubject对应的request功能来实现业务功能,自己不真正做业务。

 2、静态代理

Java">
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
interfaceSubject//抽象角色
{  
    publicvoiddoSomething();  
}
classRealSubjectimplementsSubject//真实角色
{  
    publicvoiddoSomething()  
  {  
    System.out.println("call doSomething()");  
  }  
}
classSubjectProxyimplementsSubject//代理角色
{
  //代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问。
  Subject subimpl =newRealSubject();
  publicvoiddoSomething()
  {
     System.out.println("before");//调用目标对象之前可以做相关操作
     subimpl.doSomething();
     System.out.println("after");//调用目标对象之后可以做相关操作
  }
}
 
publicclassTest
{
    publicstaticvoidmain(String[] args)throwsException
    {
        Subject sub =newSubjectProxy();
        sub.doSomething();
    }
}

  可以看到,SubjectProxy实现了Subject接口(和RealSubject实现相同接口),并持有的是Subject接口类型的引用。这样调用的依然是doSomething方法,只是实例化对象的过程改变了,结果来看,代理类SubjectProxy可以自动为我们加上了before和after等我们需要的动作。

  如果将来需要实现一个新的接口,就需要在代理类里再写该接口的实现方法,对导致代理类的代码变得臃肿;另一方面,当需要改变抽象角色接口时,无疑真实角色和代理角色也需要改变。

 

3、JDK动态代理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
interfaceSubject  
{  
    publicvoiddoSomething();  
}
classRealSubjectimplementsSubject  
{  
    publicvoiddoSomething()  
  {  
     System.out.println("call doSomething()");  
  }  
}
classProxyHandlerimplementsInvocationHandler
{
    privateObject tar;
    //绑定委托对象,并返回代理类
    publicObject bind(Object tar)
    {
        this.tar = tar;
        //绑定该类实现的所有接口,取得代理类
        returnProxy.newProxyInstance(tar.getClass().getClassLoader(),
                                      tar.getClass().getInterfaces(),
                                      this);
    }   
    publicObject invoke(Object proxy , Method method , Object[] args)throwsThrowable//不依赖具体接口实现
    {
        Object result =null;//被代理的类型为Object基类
        //这里就可以进行所谓的AOP编程了
        //在调用具体函数方法前,执行功能处理
        result = method.invoke(tar,args);
        //在调用具体函数方法后,执行功能处理
        returnresult;
    }
}
publicclassTest
{
    publicstaticvoidmain(String args[])
    {
           ProxyHandler proxy =newProxyHandler();
           //绑定该类实现的所有接口
           Subject sub = (Subject) proxy.bind(newRealSubject());
           sub.doSomething();
    }
}

  在调用过程中使用了通用的代理类包装了RealSubject实例,然后调用了Jdk的代理工厂方法实例化了一个具体的代理类。最后调用代理的doSomething方法,还有附加的before、after方法可以被任意复用(只要我们在调用代码处使用这个通用代理类去包装任意想要需要包装的被代理类即可)。当接口改变的时候,虽然被代理类需要改变,但是我们的代理类却不用改变了。这个调用虽然足够灵活,可以动态生成一个具体的代理类,而不用自己显示的创建一个实现具体接口的代理类。

回复

使用道具 举报

论坛徽章:
33
python徽章
日期:2014-09-23 14:45:41机器学习徽章
日期:2017-03-30 17:23:20推荐系统徽章
日期:2017-04-13 17:34:54python徽章
日期:2017-05-11 17:15:13spark徽章
日期:2017-05-18 16:16:45spark徽章
日期:2017-05-25 16:46:51Excel徽章
日期:2017-06-15 17:34:13高并发架构徽章
日期:2017-07-27 17:30:17Tomcat徽章
日期:2017-08-03 18:16:45大型分布式徽章
日期:2017-09-04 17:20:56python徽章
日期:2017-10-26 15:10:47Kaggle徽章
日期:2017-12-25 17:28:27
发表于 2018-7-8 23:55 | 显示全部楼层
如果能直接用老师课堂留置的作业来讲解,就较好了。看概念貌似明白了,写代码就懵了。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册 新浪微博登陆

本版积分规则

 

GMT+8, 2018-7-23 19:52 , Processed in 0.123876 second(s), 33 queries .

关闭

扫一扫加入
本版微信群