Spring AOP提供了xml配置文件以及Annotation注解的方式更方便的进行AOP的配置。当然这两种方式的最大的好处是更好的降低了代码耦合性。
XML配置的示例工程代码:
和前面的工程相比,前置通知,后置通知那几个通知类没有了,所有的通知逻辑直接放到了AllLogAdvice类的方法里:
package com.aop;
import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
public class AllLogAdvice {
private Logger logger = Logger.getLogger(AllLogAdvice.class);
// 此方法将作为前置通知
public void myBeforeAdvice(JoinPoint jionpoint) {
// 获取被调用的类名
String targetClassName = jionpoint.getTarget().getClass().getName();
// 获取被调用的方法名
String targetMethodName = jionpoint.getSignature().getName();
// 日志格式字符串
String logInfoText = "前置通知:" + targetClassName + "类的"
+ targetMethodName + "方法开始执行";
// 将日志信息写入配置的文件中
logger.info(logInfoText);
}
// 此方法将作为后置通知
public void myAfterReturnAdvice(JoinPoint jionpoint) {
// 获取被调用的类名
String targetClassName = jionpoint.getTarget().getClass().getName();
// 获取被调用的方法名
String targetMethodName = jionpoint.getSignature().getName();
// 日志格式字符串
String logInfoText = "后置通知:" + targetClassName + "类的"
+ targetMethodName + "方法开始执行";
// 将日志信息写入配置的文件中
logger.info(logInfoText);
}
// 此方法将作为异常通知
public void myThrowingAdvice(JoinPoint jionpoint, Exception e) {
// 获取被调用的类名
String targetClassName = jionpoint.getTarget().getClass().getName();
// 获取被调用的方法名
String targetMethodName = jionpoint.getSignature().getName();
// 日志格式字符串
String logInfoText = "异常通知:执行" + targetClassName + "类的"
+ targetMethodName + "方法时发生异常";
// 将日志信息写入配置的文件中
logger.info(logInfoText);
}
// 此方法将作为环绕通知
public void myAroundAdvice(ProceedingJoinPoint jionpoint) throws Throwable {
long beginTime = System.currentTimeMillis();
jionpoint.proceed();
long endTime = System.currentTimeMillis();
// 获取被调用的方法名
String targetMethodName = jionpoint.getSignature().getName();
// 日志格式字符串
String logInfoText = "环绕通知:" + targetMethodName + "方法调用前时间" + beginTime
+ "毫秒," + "调用后时间" + endTime + "毫秒";
// 将日志信息写入配置的文件中
logger.info(logInfoText);
}
}
4种通知功能用4个方法来完成了。aop.xml配置文件内容:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"> <bean id="myUserService" class="com.service.UserService"></bean> <!-- 定义日志通知,将日志切面交给Spring容器管理 --> <bean id="allLogAdvice" class="com.aop.AllLogAdvice"></bean> <!-- 进行aop配置 --> <aop:config> <!-- 配置日志切面 --> <aop:aspect id="logaop" ref="allLogAdvice"> <aop:pointcut id="logpointcut" expression="execution(* com.service.UserService.*(..))" /> <!-- 将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" throwing="e" /> <!-- 将LogAdvice日志通知中的方法指定为环绕通知 --> <aop:around method="myAroundAdvice" pointcut-ref="logpointcut"/> </aop:aspect> </aop:config> </beans>
定义pointcut的这句:
<aop:pointcut id="logpointcut" expression="execution(* com.service.UserService.*(..))" />
expression里的写法参考官网解释的
6.2.3.4节:http://docs.spring.io/spring/docs/2.0.8/reference/aop.html
除了用execution外,还可以用within,this等。
这篇文章解释也不错:http://blog.csdn.net/kkdelta/article/details/7441829
这儿第一个*通配符代表所有的返回值,第二个*代表所有方法,(..)表示任意的参数类型。也就是说com.service.UserService类下面的所有任意返回值,任意参数类型的方法都会被拦截。
再看看主测试类MainTest:
package com.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.service.IUserService;
public class MainTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext(
"aop.xml");
IUserService userService = (IUserService) context
.getBean("myUserService");
userService.addUser("ton", 56);
userService.deleteUser("ton");
}
}
这儿得到UserService的bean不再需要一个代理,而是直接用UserService定义的bean。这样的好处就是如果下次要删除通知里的逻辑,不再需要日志的功能了,我不再需要改java文件,直接在配置文件里的有关切面的配置段去掉就可以了,很好的做到了为代码解耦。
工程代码文件在附件中。。。。