面向切面编程

作者: 写代码的海怪 | 来源:发表于2020-07-01 13:09 被阅读0次

听到这个名字的时候,我真的一头雾水。其实面向切面编程(AOP)是相对面向对象编程(OOP)来说的。Emmm,还是不懂。下面就用一个事例来说明面向切面编程吧。

需求

我们现在有 DataService 一个返回数据的服务,我们想每次执行里面方法的时候都打日志。

装饰器

我们很容易想到就是用装饰器模式去实现,比如

class DataService {
      public void getData() {}
}

class Logger implements DataService {
    // 委托
    private DataService delegate;
    public Logger(DataService delegate) {
        this.delegate = delegate;
    }

    @Override
    public void getData() {
        打 Log
        delegate.getData();
    }
}

// 多态
DataService service = new Logger(new DataServiceImpl());

service.getData();

一层包一层,调用 getData() 的时候,其实是调用了 Logger.getData()。如果我们再加更多的功能,可能会变成这样:

DataService service = new Auth(new Cache(new Logger(new DataService())));

md,我都忘了要写多少个右括号了。。。这个方法是其实没什么问题,但是也有它的缺点:

  • 代码有冗余。这里并不是说包得太多层,而是每次方法你都要先打Log 再调用方法,如果 DataService 有10个方法,那么 打Log 就要写10次。
  • 这里我们注意到 Logger 是要继承 DataService 的,因此 Logger 会从 DataService 那继承一些不必要的东西。

AOP

那还有什么高招呢?这里提供一个思路:我们搞一个类 X,当调用 x.getData() 的时候,X 先打Log,再调用 dataService.getData()

???,这不废话,听起来和上面一样啊,注意这里其实是做了代理。比如,我在中国上 github.com,proxy 将请求转到日本服务器,再转到美国服务器。上 github.com 就是例子中的 getData()

而装饰器模式有点像自己抱着电脑飞到美国上 github.com。

说了那么多,先看代码。

这里先定义好代理。

public class LogProxy implements InvocationHandler {
    DataService delegate;

    public LogProxy(DataService delegate) {
        this.delegate = delegate;
    }

    @Override // method -> 原来的方法
    public Object invoke(Object proxy, Method, method, Object[] args) {
        System.out.println("Log");

        // 调用原来的方法
        Object returnValue = method.invoke(delegate, args)

        System.out.println("Finish");

        return returnValue;
    }
}

开始“网上冲浪”。

DataService service = new DataServiceImpl();

// ds 已不再是原来的 DataService,是动态生成的实例
DataService ds = Proxy.newProxyInstance(service.getClass().getClassLoader(),
                            new Class[]{DataService.class}, // 要拦截哪些接口
                            new LogProxy(service))

ds.getData(); // 会先调用 invoke 方法,再去调用 getData() 方法

但是这里的 Proxy 只能用于拦截接口的方法,不能使用类。如果要代理类的话,需要用到 ByteBuddy。

最后

AOP 其实有点像我们所说的中间件,为什么叫“切面”呢?其实这和中间件的意思差不多嘛。装饰器也可以搞定,但是缺点有很多,因此最好用 AOP。看到这么复杂的代码不禁会心一笑,这些使用了 AOP 模式的插件一定都帮我弄好了,一般不用自己实现 :)

相关文章

网友评论

    本文标题:面向切面编程

    本文链接:https://www.haomeiwen.com/subject/mfpcqktx.html