博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java动态代理、Proxy与InvocationHandler
阅读量:4293 次
发布时间:2019-05-27

本文共 2634 字,大约阅读时间需要 8 分钟。

看了好多关于代理的文章,理解和整理一下。

1、代理的基本构成

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

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

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

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

 2、静态代理

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
interface 
Subject
//抽象角色
{  
    
public 
void 
doSomething();  
}
class 
RealSubject 
implements 
Subject
//真实角色
{  
    
public 
void 
doSomething()  
  
{  
    
System.out.println( 
"call doSomething()" 
);  
  
}  
}
class 
SubjectProxy 
implements 
Subject
//代理角色
{
  
//代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问。
  
Subject subimpl = 
new 
RealSubject();
  
public 
void 
doSomething()
  
{
     
System.out.println(
"before"
); 
//调用目标对象之前可以做相关操作
     
subimpl.doSomething();
     
System.out.println(
"after"
);
//调用目标对象之后可以做相关操作
  
}
}
 
public 
class 
Test
{
    
public 
static 
void 
main(String[] args) 
throws 
Exception
    
{
        
Subject sub = 
new 
SubjectProxy();
        
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
interface 
Subject  
{  
    
public 
void 
doSomething();  
}
class 
RealSubject 
implements 
Subject  
{  
    
public 
void 
doSomething()  
  
{  
     
System.out.println( 
"call doSomething()" 
);  
  
}  
}
class 
ProxyHandler 
implements 
InvocationHandler
{
    
private 
Object tar;
    
//绑定委托对象,并返回代理类
    
public 
Object bind(Object tar)
    
{
        
this
.tar = tar;
        
//绑定该类实现的所有接口,取得代理类
        
return 
Proxy.newProxyInstance(tar.getClass().getClassLoader(),
                                      
tar.getClass().getInterfaces(),
                                      
this
);
    
}   
    
public 
Object invoke(Object proxy , Method method , Object[] args)
throws 
Throwable
//不依赖具体接口实现
    
{
        
Object result = 
null
;
//被代理的类型为Object基类
        
//这里就可以进行所谓的AOP编程了
        
//在调用具体函数方法前,执行功能处理
        
result = method.invoke(tar,args);
        
//在调用具体函数方法后,执行功能处理
        
return 
result;
    
}
}
public 
class 
Test
{
    
public 
static 
void 
main(String args[])
    
{
           
ProxyHandler proxy = 
new 
ProxyHandler();
           
//绑定该类实现的所有接口
           
Subject sub = (Subject) proxy.bind(
new 
RealSubject());
           
sub.doSomething();
    
}
}

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

 

转载地址:http://njzws.baihongyu.com/

你可能感兴趣的文章
javascript面试的5个冷门知识点
查看>>
Lucene初探
查看>>
Git简介、安装及创建版本库
查看>>
如何在JavaScript中编写一个简单的Bug跟踪器
查看>>
jQuery 效果 - 滑动
查看>>
对Java多态的深入理解
查看>>
javascript重点-表达式和运算符_优就业
查看>>
springmvc整合poi导出报表
查看>>
Oracle Data Guard延迟的原因
查看>>
java8 遍历数组的几种方式
查看>>
java基础知识(七)--Object类
查看>>
Object.prototype.toString_优就业
查看>>
JS之浏览器对象BOM
查看>>
分布式架构系列: 负载均衡技术详解
查看>>
python3安装scrapy
查看>>
python正则表达式入门一
查看>>
python正则表达式入门二
查看>>
scrapy运行
查看>>
XPATH入门
查看>>
python爬虫 CSS选择器
查看>>