什么是AOP?
AOP,即Aspect Oriented Programming(面向切面编程)。下面举例说明:
业务编程
用户增删该查:
package org.test.aop;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/** 用户管理业务控制器 */
public class UserAction {
private static Logger logger = LogManager.getLogger(UserAction.class);
// 新增用户
public void addUser() {
logger.info("addUser");
throw new RuntimeException("这是特意抛出的异常信息!");
}
// 删除用户
public void delUser() {
logger.info("delUser");
}
// 修改用户
public void modiUser() {
logger.info("modiUser");
}
// 查询用户
public void loadUser() {
logger.info("loadUser");
}
}
现在想对增删该查操作前后打印日志,以跟踪业务处理过程,该业务场景就需要AOP来处理,在不侵入业务逻辑的前提下。
AOP切面编程
日志切面:
package org.test.aop;
/** 日志切面 */
public class LogAspectJ {
// 取得日志记录器Logger
private static Logger logger = LogManager.getLogger(LogAspectJ.class);
private void anyMethod() {
}
// 前置通知
public void myBeforeAdvice(JoinPoint joinpoint) {
String classAndMethod = joinpoint.getTarget().getClass().getName()
+ "类的" + joinpoint.getSignature().getName();
logger.info("前置通知:" + classAndMethod + "方法开始执行!");
}
// 后置通知
public void myAfterReturningAdvice(JoinPoint joinpoint) {
String classAndMethod = joinpoint.getTarget().getClass().getName()
+ "类的" + joinpoint.getSignature().getName();
logger.info("后置通知:" + classAndMethod + "方法执行正常结束!");
}
// 异常通知
public void myAfterThrowingAdvice(JoinPoint joinpoint, Exception e) {
String classAndMethod = joinpoint.getTarget().getClass().getName()
+ "类的" + joinpoint.getSignature().getName();
logger.info("异常通知:" + classAndMethod + "方法抛出异常: " + e.getMessage());
}
// 最终通知
public void myAfterAdvice(JoinPoint joinpoint) {
String classAndMethod = joinpoint.getTarget().getClass().getName()
+ "类的" + joinpoint.getSignature().getName();
logger.info("最终通知:" + classAndMethod + "方法执行结束!");
}
// 做环绕通知
public Object myAroundAdvice(ProceedingJoinPoint pjp) throws Throwable {
long begintime = System.currentTimeMillis();//记下开始时间
//传递给连接点对象进行接力处理
Object result=pjp.proceed();
long endtime = System.currentTimeMillis();//记下结束时间
String classAndMethod = pjp.getTarget().getClass().getName()+
"类的"+pjp.getSignature().getName();
logger.info("环绕通知:"+classAndMethod+"方法执行结束, 耗时"+(endtime-begintime)+"毫秒!");
return result;
}
}
AOP配置
将业务编程、切面编程关联:
在Spring的配置文件中:
<?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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<bean id="userAction" class="org.test.aop.UserAction"/>
// 日志切面bean
<bean id="logAspectJ" class="org.test.aop.LogAspectJ"/>
<aop:config>
// 定义日志切面
<aop:aspect id="logaop" ref="logAspectJ">
// 日志切面所关注业务的点,即expression中匹配的哪些类、哪些方法
<aop:pointcut id="logpointcut" expression="execution(* org.test.aop.UserAction.*(..))"/>
// 在所关注的点上,进行的切面动作,即各类通知
<aop:before pointcut-ref="logpointcut" method="myBeforeAdvice"/> // 前置通知
<aop:after-returning pointcut-ref="logpointcut" method="myAfterReturningAdvice"/> // 后置通知
<aop:after-throwing pointcut-ref="logpointcut" method="myAfterThrowingAdvice" throwing="e"/> // 异常通知
<aop:after pointcut-ref="logpointcut" method="myAfterAdvice"/> // 最终通知
<aop:around pointcut-ref="logpointcut" method="myAroundAdvice"/> // 环绕通知
</aop:aspect>
</aop:config>
</beans>
AOP作用结果
userAction.addUser()运行结果:
2016-11-23 16:01:00,878 main INFO Log4j appears to be running in a Servlet environment, but there's no log4j-web module available. If you want better web container support, please add the log4j-web JAR to your web archive or server lib directory.
16:01:01.073 INFO org.test.aop.LogAspectJ myBeforeAdvice 27 main - 前置通知:org.test.aop.UserAction类的addUser方法开始执行!
16:01:01.088 INFO org.test.aop.UserAction addUser 13 main - addUser
16:01:01.089 INFO org.test.aop.LogAspectJ myAfterAdvice 51 main - 最终通知:org.test.aop.UserAction类的addUser方法执行结束!
16:01:01.089 INFO org.test.aop.LogAspectJ myAfterThrowingAdvice 43 main - 异常通知:org.test.aop.UserAction类的addUser方法抛出异常: 这是特意抛出的异常信息!
userAction.delUser()运行结果:
2016-11-23 15:02:53,971 main INFO Log4j appears to be running in a Servlet environment, but there's no log4j-web module available. If you want better web container support, please add the log4j-web JAR to your web archive or server lib directory.
15:02:54.165 INFO org.test.aop.LogAspectJ myBeforeAdvice 27 main - 前置通知:org.test.aop.UserAction类的delUser方法开始执行!
15:02:54.179 INFO org.test.aop.UserAction delUser 19 main - delUser
15:02:54.180 INFO org.test.aop.LogAspectJ myAroundAdvice 63 main - 环绕通知:org.test.aop.UserAction类的delUser方法执行结束, 耗时14毫秒!
15:02:54.180 INFO org.test.aop.LogAspectJ myAfterAdvice 51 main - 最终通知:org.test.aop.UserAction类的delUser方法执行结束!
15:02:54.180 INFO org.test.aop.LogAspectJ myAfterReturningAdvice 35 main - 后置通知:org.test.aop.UserAction类的delUser方法执行正常结束!
在日志切面中,Spring AOP的作用就是,将日志切面中的各类通知作用在其所关注的业务点,以打印相关日志,跟踪业务处理过程。需要注意的是,业务编程和AOP编程是解耦的。
这里只是AOP应用的一个业务场景而已,以此向其他业务场景类推,但原理和流程一样,面向切面编程很形象的阐述了AOP。