hod method = methodSignature.getMethod();
System.out.println(method.getName() + "()方法开始时间:" + System.currentTimeMillis());
try {
pjp.proceed();
System.out.println(method.getName() + "()方法结束时间:" + System.currentTimeMillis());
} catch (Throwable e) {
}
}
}
}
到第8行的代码与第12行的代码分别打印方法开始执行时间与方法结束执行时间。我这里写得稍微复杂点,使用了<aop:around>的写法,其实也可以拆分为<aop:before>与<aop:after>两种,这个看个人喜好。
这里多说一句,切面方法printTime本身可以不用定义任何的参数,但是有些场景下需要获取调用方法的类、方法签名等信息,此时可以在printTime方法中定义JointPoint,Spring会自动将参数注入,可以通过JoinPoint获取调用方法的类、方法签名等信息。由于这里我用的<aop:around>,要保证方法的调用,这样才能在方法调用前后输出时间,因此不能直接使用JoinPoint,因为JoinPoint没法保证方法调用。此时可以使用ProceedingJoinPoint,ProceedingPointPoint的proceed()方法可以保证方法调用,但是要注意一点,ProceedingJoinPoint只能和<aop:around>搭配,换句话说,如果aop.xml中配置的是<aop:before>,然后printTime的方法参数又是ProceedingJoinPoint的话,Spring容器启动将报错。
接着看一下aop.xml的配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<bean id="daoImpl" class="org.xrq.spring.action.aop.DaoImpl" />
<bean id="timeHandler" class="org.xrq.spring.action.aop.TimeHandler" />
<aop:config>
<aop:pointcut id="addAllMethod" expression="execution(* org.xrq.spring.action.aop.Dao.*(..))" />
<aop:aspect id="time" ref="timeHandler">
<aop:before method="printTime" pointcut-ref="addAllMethod" />
<aop:after method="printTime" pointcut-ref="addAllMethod" />
</aop:aspect>
</aop:config>
</beans>
我不大会写expression,也懒得去百度了,因此这里就拦截Dao下的所有方法了。测试代码很简单:
/**
* @author 五月的仓颉http://www.cnblogs.com/xrq730/p/7003082.html
*/
public class AopTest {
@Test
@SuppressWarnings("resource")
public void testAop() {
ApplicationContext ac = new ClassPathXmlApplicationContext("spring/aop.xml");
Dao dao = (Dao)ac.getBean("daoImpl");
dao.insert();
System.out.println("----------分割线----------");
dao.delete();
System.out.println("----------分割线----------");
dao.update();
}
}
结果就不演示了。到此我总结一下使用AOP的几个优点:
- 切面的内容可以复用,比如TimeHandler的printTime方法,任何地方需要打印方法执行前的时间与方法执行后的时间,都可以使用TimeHandler的printTime方法
- 避免使用Proxy、CGLIB生成代理,这方面的工作全部框架去实现,开发者可以专注于切面内容本身
- 代码与代码之间没有耦合,如果拦截的方法有变化修改配置文件即可
下面用一张图来表示一下AOP的作用:
我们传统的编程方式是垂直化的编程,即A–>B–>C–>D这么下去,一个逻辑完毕之后执行另外一段逻辑。但是AOP提供了另外一种思路,它的作用是在业务逻辑不知情(即业务逻辑不需要做任何的改动)的情况下对业务代码的功能进行增强,这种编程思想的使用场景有很多,例如事务提交、方法执行之前的权限检测、日志打印、方法调用事件等等。
AOP使用场景举例
上面的例子纯粹为了演示使用,为了让大家更加理解AOP