在多个模块的代码中都有功能相同的代码段(比如日志),你可能在多处(eg: 连接前,连接中,断开之后等类似的周期)去记录各种日志数据,然而这种代码与你的业务逻辑代码又没啥大关系,反而让你的代码显得很乱,所谓切面就是提取出相同的功能封装好,然后动态代理的插入到原有的业务逻辑。
书接上回,我们看一下下面这个皇帝上朝的切面应用例子:
public class worker {
private PrintStream stream;
public worker (PrintStream stream) {
this.stream = stream;
}
//上朝之前
public void workBefore() {
stream.println("我要去上班了");
}
//上朝之后
public void workAfter() {
stream.println("我已经下班了");
}
}
我们需要实现就是在上朝前调用workBefore,上朝之后调用workAfter,
public class Emperor implements King {
//皇帝的事务接口(看我的学习系列一就知道这是什么意思)
private Transaction transaction;
private Worker worker;
public Emperor (Transaction transaction, Worker worker) {
this.worker = worker;
this.transaction = transaction;
}
public void onWork() throw WorkException {
worker.workBefore();
transaction.work();
worker.workAfter();
}
}
之后再将Worker bean注入到Emperor的构造器中(这个看我的系列一中已有介绍)。
不过这里有一个问题就是皇帝需要知道worker才可以,但是很多逻辑下皇帝不应该关心这些,应该是单方面worker要知道皇帝上朝,而皇帝不需要去担心,所以这里就需要aop来解决了。
aop配置文件大致如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="..."
...
...
...>
<bean id="emperor" class="...">
<constructor-arg ref="transaction" />
</bean>
<bean id="transaction" class="...">
<constructor-arg value="#{T(System).out}" />
</bean>
<bean id="worker" class="...">
<constructor-arg value="#{T(System).out}" />
</bean>
<aop:config>
<aop:aspect ref="worker">
<aop:pointcut id="work" expression="execution(* *.onWork(..))" />
<aop:before pointcut-ref="work" method="workBefore" />
<aop:after pointcut-ref="work" method="workAfter" />
</aop:aspect>
</aop:config>
</beans>
这只是简单的例子,之后进一步补充,待续。。。