基于 Schema 的AOP实现
基于 Schema 的 AOP 通过 aop 命名空间来定义切面、切入点以及声明通知。在 Spring 配置文件中,所有的切面和通知都必须定义在<aop:config>
元素内部。
首先新建类 AllLogAdvice,并在类中编写用于演示的各种类型通知,在定义通知方法时传入一个连接点 JoinPoint 参数,通过该参数可以获取目标对象的类名、目标方法名和目标方法参数等信息:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57public class AllLogAdvice
{
private Logger logger=Logger.getLogger(AllLogAdvice.class);
//此方法将作为前置通知
public void myBeforeAdvice(JoinPoint joinpoint)
{
//获取被调用的类名
String targetClassName=joinpoint.getTarget().getClass().getName();
//获取被调用的方法名
String targetMethodName=jointpoint.getSignature().getName();
//日志格式字符串
String logInfoText="前置通知:"+ targetClassName + "类的" + targetMethodName + "方法开始执行";
//将日志信息写入配置的文件中
logger.info(logInfoText);
}
//此方法将作为后置通知
public void myAfterReturnAdvice(JoinPoint joinpoint)
{
//获取被调用的类名
String targetClassName=joinpoint.getTarget().getClass().getName();
//获取被调用的方法名
String targetMethodName=jointpoint.getSignature().getName();
//日志格式字符串
String logInfoText="后置通知:"+ targetClassName + "类的" + targetMethodName + "方法开始执行";
//将日志信息写入配置的文件中
logger.info(logInfoText);
}
//此方法将作为异常通知
public void myThrowingAdvice(JoinPoint joinpoint,Exception e)
{
//获取被调用的类名
String targetClassName=joinpoint.getTarget().getClass().getName();
//获取被调用的方法名
String targetMethodName=jointpoint.getSignature().getName();
//日志格式字符串
String logInfoText="异常通知:执行"+ targetClassName + "类的" + targetMethodName + "方法时发生异常";
//将日志信息写入配置的文件中
logger.info(logInfoText);
}
//此方法将作为环绕通知
public void myAroundAdvice(ProceedingJoinPoint joinpoint) throws Throwable
{
long beginTime=System.currentTimeMillis();
joinpoint.proceed();
long endTime=System.currentTimeMillis();
//获取被调用的方法名
String targetMethodName=jointpoint.getSignature().getName();
//日志格式字符串
String logInfoText="环绕通知:"+ targetMethodName + "方法调用前时间" + beginTime + "毫秒," + 调用后时间 + endTime + "毫秒";
//将日志信息写入配置的文件中
logger.info(logInfoText);
}
}
然后在 src 目录下新建一个配置文件 aop.xml,在配置文件中采用 AOP 配置方式实现 AOP 功能。从而将日志通知 AllLogAdvice 与业务组件 UserBiz 这两个原本互不相关的类和接口,通过在配置文件 aop.xml 中进行 AOP 装配后,实现了将 AllLogAdvice 类中的各种通知切入到 UserBiz 中,以实现预期的日志记录。aop.xml 配置文件的内容如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43<?xml version="1.0" encoding="UTF-8">
<beans
xmlns="http://www.springframework.org/shcema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.1.xsd">
<!-- 配置创建 UserDAOImpl 的实例 -->
<bean id="userDAO" class="com.shw.dao.UserBizImpl"/>
<!-- 配置创建 UserBizImpl 的实例 -->
<bean id="userBiz" class="com.shw.biz.UserBizImpl">
<!-- 依赖注入数据访问层组件 -->
<property name="userDAO" ref="userDAO"/>
</bean>
<!-- 定义日志通知、将日志切面交给 Spring 容器管理 -->
<bean id="allLogAdvcie" class="com.shw.aop.AllLogAdvice"/>
<!-- 进行 aop 配置 -->
<aop:config>
<!-- 配置日志切面 -->
<aop:aspect id="logaop" ref="allLogAdvcie">
<!-- 定义切入点,切入点采用正则表达式 execution(* com.shw.biz.UserBiz.*.(..)),含义是对 com.shw.biz.UserBiz 中的所有方法都尽心拦截 -->
<aop:pointcut id="logpointcut" expression="execution(* com.shw.biz.UserBiz.*(..))"/>
<!-- 将 LogAdvice 日志通知中的 myBeforeAdvice 方法指定为前置通知 -->
<aop:before method="myBeforeAdvice" pointcut-ref="logpointcut"/>
<!-- 将 LogAdvice 日志通知中的 myAfterReturnAdvice 方法指定为后置通知 -->
<aop:after-returning method="myAfterReturnAdvice" pointcut-ref="logpointcut"/>
<!-- 将 LogAdvice 日志通知中的方法指定为异常通知 -->
<aop:after-throwing method="myThrowingAdvice" pointcut-ref="logpointcut" throwint="e"/>
<!-- 将 LogAdvice 日志通知中的方法指定为环绕通知 -->
<aop:around method="myAroundAdvice" pointcut-ref="logpointcut"/>
</aop:aspect>
</aop:config>
</beans>