为了复杂起见, 例子没有没有使用任何第三方的AOP Framework, 而是利用Java语言自身自带的静态代理功能来实现AOP.
让我们先回到AOP自身, AOP主要应用于日志记录, 功能统计, 平安控制, 事务处理等方面。 它的主要意图就要将日志记录, 功能统计, 平安控制等等代码从商业逻辑代码中清楚的划分出来, 我们可以把这些行为一个一个单独看作系统所要处理的成果, 就是所谓的面向成果的编程(不知将AOP译作面向成果的编程能否欠妥)。 经过对这些行为的分别, 我们希望可以将它们独立地配置到商业办法中, 而要改动这些行为也不需求影响到商业办法代码。
假设系统由一系列的BusinessObject所完成业务逻辑功能, 系统要求在每一次业务逻辑处理时要做日志记录。 这里我们略去具体的业务逻辑代码。
public interface BusinessInterface {
public void processBusiness();
}
public class BusinessObject implements BusinessInterface {
private Logger logger = Logger. getLogger(this. getClass(). getName());
public void processBusiness(){
try {
logger("start to processing. . . ");
//business logic here.
System. out. println(“here is business logic”);
logger("end processing. . . ");
} catch (Exception e){
logger("exception happends. . . ");
//exception handling
}
}
}
这里处理商业逻辑的代码和日志记录代码混合在一起, 这给日后的维护带来一定的困难, 并且也会形成少量的代码重复。 完全相反的log代码将出如今系统的每一个BusinessObject中。
依照AOP的思想, 我们应该把日志记录代码分别出来。 要将这些代码分别就涉及到一个成果, 我们必需知道商业逻辑代码何时被调用, 这样我们好插入日志记录代码。 普通来说要截获一个办法, 我们可以采用回调办法或者静态代理。 静态代理普通要愈加灵敏一些, 目前少数的AOP Framework也大都采用了静态代理来实现。
歌瑞尔 这里我们也采用静态代理作为例子。
JDK1. 2以后提供了静态代理的支持, 顺序员经过实现java. lang. reflect. InvocationHandler接口提供一个执行处理器, 然后经过java. lang. reflect. Proxy得到一个代理对象, 经过这个代理对象来执行商业办法, 在商业办法被调用的同时, 执行处理器会被自动调用。
有了JDK的这种支持, 我们所要做的仅仅是提供一个日志处理器。
public class LogHandler implements InvocationHandler {
private Logger logger = Logger. getLogger(this. getClass(). getName());
private Object delegate;
public LogHandler(Object delegate){
this. delegate = delegate;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object o = null;
try {
logger("method stats. . . " + method);
o = method. invoke(delegate, args);
logger("method ends. . . " + method);
} catch (Exception e){
logger("Exception happends. . . ");
//excetpion handling.
}
return o;
}
}
如今我们可以把BusinessObject里面的一切日志处理代码全部去掉了。
public class BusinessObject implements BusinessInterface {
private Logger logger = Logger. getLogger(this. getClass(). getName());
public void processBusiness(){
//business processing
System. out. println(“here is business logic”);
}
}
客户端调用商业办法的代码如下,
BusinessInterface businessImp = new BusinessObject();
InvocationHandler handler = new LogHandler(businessImp);
BusinessInterface proxy = (BusinessInterface) Proxy. newProxyInstance(
businessImp. getClass(). getClassLoader(),
businessImp. getClass(). getInterfaces(),
handler);
proxy. processBusiness();
顺序输入如下:
INFO: method stats. . .
here is business logic
INFO: method ends. . .
至此我们的第一次小尝试算是完成了。 可以看到, 采用AOP之后, 日志记录和业务逻辑代码完全分开了, 以后要改动日志记录的话只需求修正日志记录处理器就行了, 而业务对象自身(BusinessObject)无需做任何修正。 并且这个日志记录不会形成重复代码了, 一切的商业处理对象都可以重用这个日志处理器。