现在的位置: 首页 > 综合 > 正文

也谈用Java动态代理实现AOP(面向方面编程)

2013年02月09日 ⁄ 综合 ⁄ 共 4258字 ⁄ 字号 评论关闭
今天读了一篇谈面向方面实现的文章《谈用Java动态代理实现AOP》,颇有感触。经过思考,发现可以用这种方法经过改良实现多种AOP的模式。下面一一道来:

一、动态横切

假设现在存在一个类Business,如下:
public class Business{
    public void work(){
        System.out.println("working...");
    }
}
我们要对Business类的方法work执行前后添加日志,而条件不允许我们修改Business类的源码(比如根本没有源码)。通过对AOP的了解,我们可以通过编写一个方面(Aspect)来实现日志的功能。
先定义一个IBusiness接口如下:
public interface IBusiness{
    void work();
}

扩展Business类实现我们自己的MyBusiness类:
public class MyBusiness extends Business implements IBusiness{
}

MyBusiness中不需要有任何实现的代码。我们可以看到,Business类不需要实现任何接口,这与《谈用Java动态代理实现AOP》中的实现不同。而这与现实的情况往往是相符的。

下面定义一个方面,叫做LogAspect:
public class LogAspect implements InvocationHandler{
    private IBusiness busi;
    public LogAspect(IBusiness busi){
        this.busi = busi;
    }
  
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object ret = null;
        if(method.getName().equals("work")){
            System.out.println("(LogAspect)before work");
            ret = method.invoke(busi, args);
            System.out.println("(LogAspect)after work");
        }else{
            ret = method.invoke(proxy, args);
        }
        return ret;
    }
}

下面构造一个代理来访问Business类的实例:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
...

MyBusiness busi = new MyBusiness();
LogAspect logAspect = new LogAspect(busi);
IBusiness proxyBusi = (IBusiness)Proxy.newProxyInstance(
                busi.getClass().getClassLoader(),
                new Class[]{IBusiness.class}, logAspect);

proxyBusi.work();

下面为执行的结果:
(LogAspect)before work
working
(LogAspect)after work

二、为Business类增加多个动态横切
《谈用Java动态代理实现AOP》提到:“当然在实际应用中,这个例子就显得太粗糙了。由于JDK的动态代理并没有直接支持一次注册多个InvocationHandler,那么我们对业务处理方法既要日志记录又要性能统计时,就需要自己做一些变通了。” 但是事实情况并不是这样,虽然不能做到一次注册多个InvocationHandler,但是可以分多次注册。下面是实现方法:

定义第二的方面Aspect2:
public class Aspect2 implements InvocationHandler{
    private IBusiness busi;
    public Aspect2(IBusiness busi){
        this.busi = busi;
    }
  
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object ret = null;
        if(method.getName().equals("work")){
            System.out.println("(Aspect2)before work");
            ret = method.invoke(busi, args);
            System.out.println("(Aspect2)after work");
        }else{
            ret = method.invoke(proxy, args);
        }
        return ret;
    }
}

构造动态代理:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
...

MyBusiness busi = new MyBusiness();
LogAspect logAspect = new LogAspect(busi);
IBusiness proxyBusi = (IBusiness)Proxy.newProxyInstance(
                busi.getClass().getClassLoader(),
                new Class[]{IBusiness.class}, logAspect);

Aspect2 aspect2 = new Aspect2(proxyBusi);
proxyBusi = (IBusiness)Proxy.newProxyInstance(
                busi.getClass().getClassLoader(),
                new Class[]{IBusiness.class}, aspect2);

proxyBusi.work();

下面为执行的结果:
(Aspect2)before work
(LogAspect)before work
working
(LogAspect)after work
(Aspect2)after work

三、静态横切
其实就是增加新的方法到已有的类或让已有的类实现新的接口。
假设我们要增加的一个新的接口如下:
public interface IBusiness2{
    void work2();
}

有两种方法:第一种是让MyBusiness类实现IBusiness2接口,很简单,这里就不再实现了;第二种是通过InvocationHandler来实现。:

增加接口IBusiness3:
public interface IBusiness3 extends IBusiness, IBusiness2{

}

我们可以在InvocationHandler中实现work方法,比如LogAspect中:
public class LogAspect implements InvocationHandler{
    private IBusiness busi;
    public LogAspect(IBusiness busi){
        this.busi = busi;
    }
   
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object ret = null;
        if(method.getName().equals("work")){
            System.out.println("(LogAspect)before work");
            ret = method.invoke(busi, args);
            System.out.println("(LogAspect)after work");
        }else if(method.getName().equals("work2")){
            ret = Business_work2();
        }else{
            ret = method.invoke(proxy, args);
        }
        return ret;
    }
    
    protected void Business_work2(){
        System.out.println("work2");
    }
}

下面构造动态代理并调用work2方法:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
...

MyBusiness busi = new MyBusiness();
LogAspect logAspect = new LogAspect(busi);
IBusiness3 proxyBusi = (IBusiness3)Proxy.newProxyInstance(
                busi.getClass().getClassLoader(),
                new Class[]{IBusiness3.class}, logAspect);
proxyBusi.work();
proxyBusi.work2();

下面为执行的结果:
(LogAspect)before work
working
(LogAspect)after work
work2

参考资料:
谈用Java动态代理实现AOP
AOP 解决紧密耦合的难题

抱歉!评论已关闭.