aop原理学习——动态代理

aop:面向切面编程。

我的理解就是:对于多个实例对象,把它们码放在一起,在一个或多个特定位置切上一刀,在这个切面的位置上做一些统一的操作。

aop最常用的场景就是日志。

一般来说我们希望在某些函数调用前后记录日志。最容易想到的办法如下:

每次在调用函数的前后加上日志信息。

但如果要对所有对象调用say()函数进行日志,照这样的方法就会出现如下情况

这就产生了面向切面的需求,也就是:我要对所有对象在say函数上切一刀,在这个切面上做一些日志。

现利用java的动态代理方法来实现对函数调用进行代理,可以在代理函数调用中对实际的调用进行日志。

假设有一个接口声明了函数say:

有两个类分别实现了该接口:

我希望这两个类的实例在调用say的前后都能做一下日志。

可以用到java反射中的一些编程接口。

最核心的的方法为,调用

Object java.lang.reflect. Proxy .newProxyInstance( ClassLoader loader, Class <?>[] interfaces, InvocationHandler h) throws IllegalArgumentException

 

它是一个静态方法,需要提供一个类加载器,接口和一个实现InvocationHandler的代理实例,返回一个对应的代理类。

其中第一个参数表示被代理的对象的类的加载器,这里指的就是Hello和Bye的类加载器,第二个参数表示被代理类的接口,这里指的就是ISay。最后一个参数是一个实现InvocationHandler的代理实例,他需要实现 Object invoke(Object proxy, Method method, Object [] arg2) throws Throwable

其中proxy就是这个代理本身(可以暂时这样理解,实际有区别)。method就是被代理的对象的当前被调用函数,arg2是这个被调用函数的参数。

 

我要做的事情是这样的,一般而言产生一个实例对象往往用new来实现,比如ISay h=new Hello(); 而当调用h.say()时,函数会直接被调用。现在我希望劫持这个对象,让的函数调用也可以自定义的进行,此处就是让它在调用say时前后加上日志。

怎么劫持这个对象,就是建立一个该对象的代理,当要调用say方法时委托这个代理对象来完成实际say方法的调用,而代理则可以在实际调用say方法时做一些动作。

实现的方法如下:

这是一个函数调用代理类,首先它实现了invoke方法。其次他有一个delegate成员,类型是Object,即MyProxy可以成为任何对象的函数调用代理,也就是说他可以劫持任何类对象,使得被劫持对象的某个函数被调用时,自动调用invoke方法,你可以在这个方法内自定义被劫持对象的方法会被怎么调用,在此处,当被劫持的任何函数被调用的前后都会打印一些日志。

这是一个工厂类,只有一个静态方法,他接受一个Class类型的参数,返回一个该类的代理对象,即这个类对象已经被劫持,返回的是这个劫持者,但是它的外表看上去没有任何特别,它的类加载器是和原来一样,并且它实现的接口也和原来一样。在getInstance里,首先根据类来建立实例,这就和new的效果一样,然后用MyProxy的实例来做它的函数调用代理,即这个对象的任何函数调用都要经proxy来处理。最后返回用Proxy.newProxyInstance方法产生的代理对象。

测试主函数如下:

可见用ProxyFactory产生的对象和用new产生的对象在调用者看来没有区别,但实际却被劫持了,所以运行结果为:

do before...
Hello!
do after...
do before...
Bye bye!
do after...

但是j2se标准接口中只提供了对实现接口的类的动态代理,所以被代理类必须实现某个接口,否则不能对某个函数进行代理。如果要对普通类进行动态代理,这里不做讨论。

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值