摘要
本文讲解了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反射的一个经典应用。