谈谈什么是AOP以及动态代理技术

摘要

本文讲解了aop的基本概念,并且简要的介绍了其实现原理。

AOPのwhy以及what

我们都知道,软件的良好组织应该是分模块的,而且这种模块最好是垂直结构的。OOP思想正好契合这种设计模式。但是在我们的实际软件组织中,有些功能总是会破坏这种结构,设想下面的场景,在程序设计中,我们最常用的功能便是日志功能了,我们无法把这些日志代码集中管理起来,他总是会散布在我们的代码中,将我们的代码污染。又或者我们需要在现有业务逻辑上加入一些特定的功能,这些功能也许或许每个模块都需要,比如说我们需要监测每个模块的性能,又或者为每个模块添加一些安全检查逻辑,但是又不能为使用该模块的使用者带来麻烦,也就是说我们想用非侵入式编程的方法实现此功能。在面向对象中,我们只能采用继承式的方法来添加这些逻辑。但是这样最明显的问题及时,代码组织会迅速膨胀。加入说我们原先有100个具体的类,我们想为每个类添加打印日志功能,这样我们就需要继承这100个类,重写每一个需要打印日志的方法。久而久之,我们的软件一定会变得难以管理。AOP就是为了解决这个问题而提出的。它采用了动态代理的思想,实现了上述的功能。

动态代理

为方便讲述动态代理,用下面的具体例子来帮助理解,假设我们软件模块中有这样的一个类SomeTask,我们现在想为这个类添加一些额外的功能。比如我现在想进行一些安全检查的代码。我们应该怎么办?(我,还能怎么办,打开SomeTask的代码,进入到具体方法,改就完事了。AOP:滚!)下面用伪代码进行描述:

interface Task{
    public void execute(args:Object[]);
}
Class SomeTask implements Task {
    public void execute(args:Object[]) {
        
    }
}
interface SecurityCheck{
    public boolean securityCheck();
}
class SecurityCheckImpl implements SecurityChcek{
    public boolean securityCheck(){
        
    }
}

假如我们不允许对SomeTask的源代码进行改动,我们能想到最直接的方法便是面向白盒编程,也及时继承Task,然后进行方法的重写。代码如下:

class TaskWithSecurityCheck implements Task{
    private Task task;
    private SecurityCheck sc;
    public TaskWithSecurityCheck(Task t,SecurityCheck s){
        task = t;
        sc = s;
    }
    @Override
    public void execute(args:Object[]) {
        boolean success = sc.securityCheck();
        if(success) task.execute();
        else {
            System.out.prrintln("securiy check fail forbbiden execute the task");
        }
    }
}

嗯,这样的代码也还可以,当我们的软件规模不大时,但是设想一下,假如我们需要为每个模块假如这样的安全检查呢,头铁的可以继续刚,我还是去寻找更好的解决方案了。这个时候,实际上需要我们的动态代理出场了,哦,对了,上面的模式叫做静态代理模式。

动态代理可以实现将欲添加的功能完全抽象出来,那个模块想要添加这个功能,动态的添加就好了,非常的方便。话不多说,我们直接看代码:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class SecurityCheckProxy implements InvocationHandler {
	private Object target;
    private SecurityChcke sc;
	public CalTaskTimeProxy(Object t,SecurityCheck sc) {
		this.target = t;
        this.sc = sc;
	}
	@SuppressWarnings("unchecked")
	public  <T> T create() {
		return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
	}
	@Override
	public Object invoke(Object proxy,Method method,Object[] args) throws Throwable{
		//before();
		Object result = null;
               boolean success = sc.securityCheck();
		try {
                    if(success) result = method.invoke(target,args);
                    return result;
		} catch (IllegalAccessException e) {
		}
                finally{
                    if(result == null) {
                    System.out.println("task forbbiden execute cause security check fail");
             }
         }
	}
}

我们的客户端调用代码如下:

public void main(String[] args) {
    Task task = new SecurityCheckProxy(new SomeTask();
        			new SecurityCheckImpl()).create();
    task.execute();
}

可以看出,在客户端的使用除了多了需要配置的代理以外,没有任何的异常,这样我们就实现了对于原先代码不进行任何改动的前提下,从而添加了我们想要的新功能。实际上这也是AOP实现的基本思想。同时也是java反射的一个经典应用。

原文地址:https://www.cnblogs.com/zhangshoulei/p/13280793.html