java代理机制总结

代理概念:为某个对象提供一个代理,以控制对这个对象的访问。

代理类的作用:代理类负责请求的预处理、过滤、将请求分派给委托类处理、以及委托类执行完请求后的后续处理。(比如在AOP编程中的事务管理,日志管理,权限控制等,这些非核心业务逻辑的代码交由代理类来处理,这也是为什么说AOP是建立在动态代理机制上的),使用一个代理类可以代理多个委托类。

使用代理类的优点:可以隐藏委托类的实现;可以实现客户与委托类间的解耦,在不修改委托类代码的情况下能够做一些额外的处理。

静态代理:若代理类在程序运行前就已经存在,那么这种代理方式被成为 静态代理 ,这种情况下的代理类通常都是我们在Java代码中定义的。 通常情况下, 静态代理中的代理类和委托类会实现同一接口或是派生自相同的父类。静态代理可以通过聚合来实现,让代理类持有一个委托类的引用即可,这样代理类便可以根据传入的引用代理多个委托类,并且可以在代理类上加额外的代码,但不改变原来的委托类。

下面我们用Vendor类代表生产厂家,BusinessAgent类代表微商代理,来介绍下静态代理的简单实现,委托类和代理类都实现了Sell接口,Sell接口的定义如下:

publicinterface Sell { void sell(); voidad();
  
}
Vendor类的定义如下:
publicclass Vendor implementsSell { public void sell() {
  
System.out.println("In sell method");
  
}public voidad() {
  
System,out.println("ad method")
  
}
  
}
BusinessAgent类定义如下
publicclass BusinessAgent implements Sell {
  
privateVendor mVendor;
  
publicBusinessAgent(Vendor vendor) {
  
this.mVendor = vendor;
  
}
  
publicvoid sell() {
  
System.out.println("before");
  
mVendor.sell();
  
System.out.println("after");
  
}
  
publicvoid ad() {
  
System.out.println("before");
  
mVendor.ad();
  
System.out.println("after");
  
}
  
}
从以上代理类代码中我们可以了解到,通过静态代理实现我们的需求需要我们在每个方法中都添加相应的逻辑,这里只存在两个方法所以工作量还不算大,假如Sell接口中包含上百个方法呢?这时候使用静态代理就会编写许多冗余代码。通过使用动态代理,我们可以做一个“统一指示”,从而对所有代理类的方法进行统一处理,而不用逐一修改每个方法。这就是动态代理的由来。

动态代理:

(1)InvocationHandler接口
在使用动态代理时,我们需要定义一个位于代理类与委托类之间的中介类,这个中介类被要求实现InvocationHandler接口,这个接口的定义如下:

1
2
3
4
5
publicinterface InvocationHandler {
  
Object invoke(Object proxy, Method method, Object[] args);
  
}
从InvocationHandler这个名称我们就可以知道,实现了这个接口的中介类用做“调用处理器”。当我们调用代理类对象的方法时,这个“调用”会转送到invoke方法中,代理类对象作为proxy参数传入,参数method标识了我们具体调用的是代理类的哪个方法,args为这个方法的参数。这样一来,我们对代理类中的所有方法的调用都会变为对invoke的调用,这样我们可以在invoke方法中添加统一的处理逻辑(也可以根据method参数对不同的代理类方法做不同的处理)。

(2)委托类的定义
动态代理方式下,要求委托类必须实现某个接口,这里我们实现的是Sell接口。委托类Vendor类的定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
publicclass Vendor implementsSell {
  
publicvoid sell() {
  
System.out.println("In sell method");
  
}
  
publicvoid ad() {
  
System,out.println("ad method")
  
}
  
}

(3)中介类
上面我们提到过,中介类必须实现InvocationHandler接口,作为调用处理器”拦截“对代理类方法的调用。中介类的定义如下:

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
publicclass DynamicProxy implements InvocationHandler {
  
privateObject obj; //obj为委托类对象;
  
publicDynamicProxy(Object obj) {
  
this.obj = obj;
  
}
  
@Override
  
publicObject invoke(Object proxy, Method method, Object[] args)throws Throwable {
  
System.out.println("before");
  
Object result = method.invoke(obj, args);
  
System.out.println("after");
  
returnresult;
  
}
  
}
从以上代码中我们可以看到,中介类持有一个委托类对象引用,在invoke方法中调用了委托类对象的相应方法(第11行),看到这里是不是觉得似曾相识?通过聚合方式持有委托类对象引用,把外部对invoke的调用最终都转为对委托类对象的调用。这不就是我们上面介绍的静态代理的一种实现方式吗?实际上,中介类与委托类构成了静态代理关系,在这个关系中,中介类是代理类,委托类就是委托类; 代理类与中介类也构成一个静态代理关系,在这个关系中,中介类是委托类,代理类是代理类。也就是说,动态代理关系由两组静态代理关系组成,这就是动态代理的原理。下面我们来介绍一下如何”指示“以动态生成代理类。

(4)动态生成代理类
动态生成代理类的相关代码如下:

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
publicclass Main {
  
publicstatic void main(String[] args) {
  
//创建中介类实例
  
DynamicProxy inter =new DynamicProxy(newVendor());
  
//加上这句将会产生一个$Proxy0.class文件,这个文件即为动态生成的代理类文件
  
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
  
//获取代理类实例sell
  
Sell sell = (Sell)(Proxy.newProxyInstance(Sell.class.getClassLoader(),new Class[] {Sell.class}, inter));
  
//通过代理类对象调用代理类方法,实际上会转到invoke方法调用
  
sell.sell();
  
sell.ad();
  
}
  
}

在以上代码中,我们调用Proxy类的newProxyInstance方法来获取一个代理类实例。这个代理类实现了我们指定的接口并且会把方法调用分发到指定的调用处理器。这个方法的声明如下:

代码如下:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException

方法的三个参数含义分别如下:
loader:定义了代理类的ClassLoder;
interfaces:代理类实现的接口列表
h:调用处理器,也就是我们上面定义的实现了InvocationHandler接口的类实例
我们运行一下,看看我们的动态代理是否能正常工作。我这里运行后的输出为:

说明我们的动态代理确实奏效了。

上面我们已经简单提到过动态代理的原理,这里再简单的总结下:首先通过newProxyInstance方法获取代理类实例,而后我们便可以通过这个代理类实例调用代理类的方法,对代理类的方法的调用实际上都会调用中介类(调用处理器)的invoke方法,在invoke方法中我们调用委托类的相应方法,并且可以添加自己的处理逻辑。注意的是这里有一个中间类,中间类并不是动态代理类。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值