一,前言
利用SpringAOP切面完成對java方法的運行時間計算
二,准備
創建JavaWeb項目,配置Spring,創建方法類,測試類,切面類
三,代碼實現
1.配置xml文件
<!-- 定義目標對象 --> <bean id="stuimpl" class="com.stu.impl.StuImpl"></bean> <!-- 定義切面對象 --> <bean id="log" class="com.stu.Log"></bean> <!-- 切面配置 --> <aop:config> <!-- 切入點表達式:execution:具體到方法,within:具體到類,類中的所有方法,*:任意字符 ..:多層 execution(public void com.aaa.aop3.BookImpl.add(int)) execution(* * com..*.select*(..)) within(com.aaa.aop3.BookImpl):com.aaa.aop3.BookImpl下的所有方法 within(com.aaa.aop3.*):com.aaa.aop3包下所有類中所有方法 --> <!-- 定義一個可以被多個切面共享的切入點 --> <!-- <aop:pointcut expression="within(com.aaa.aop3.BookImpl)" id="points"/> --> <aop:pointcut expression="execution(* com.stu.impl.StuImpl.*(..))" id="points"/> <!-- 將id=log的對象作為切面使用 --> <aop:aspect ref="log"> <!-- method:方法 pointcut-ref:切入點 同時配置后置/異常/最終通知時:按照配置的先后順序執行 -->
<!-- before:前置通知,總是在連接點調用前執行 --> <!-- <aop:before method="start" pointcut-ref="points"/> --> <!-- 后置通知:在方法正常執行完成之后調用 --> <!-- <aop:after-returning method="afterReturning" pointcut-ref="points"/> --> <!-- 異常通知:在方法異常執行之后調用 --> <!-- <aop:after-throwing method="afterThrowing" pointcut-ref="points" throwing="e"/> --> <!-- 最終通知:在方法執行完成之后調用 --> <!-- <aop:after method="after" pointcut-ref="points"/> --> <!-- 環繞通知:圍繞方法的執行前后執行 --> <aop:around method="around" pointcut="execution(* com.stu.impl.StuImpl.*(..))"/> </aop:aspect> </aop:config>
2.Log類
package com.stu; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.Signature; public class Log { //定義方法開始時間和結束時間 long startTime; long afterTime; public void start() { //獲取系統當前時間的毫秒數 startTime = System.currentTimeMillis(); System.out.println("前置通知before"); } // JoinPoint:連接點對象 public void after(JoinPoint jp) { System.out.println("最終通知after"); afterTime = System.currentTimeMillis(); Signature signature = jp.getSignature(); System.out.println(signature.getDeclaringTypeName()+"."+signature.getName()+"方法執行了"+(afterTime-startTime)+"ms"); } public void afterReturning() { System.out.println("后置通知afterReturning"); } public void afterThrowing(JoinPoint jp,Exception e) throws Exception { System.out.println("異常通知afterThrowing"); System.out.println("發生異常,異常的原因是" + e.getMessage()); } /** * ProceedingJoinPoint:正在執行的連接點,只能寫在環繞通知中 * * @return返回值表示的連接點的返回值 */ public Object around(ProceedingJoinPoint pjp) { Object obj = null; System.out.println("環繞通知around"); try { System.out.println("環繞前置通知"); startTime = System.currentTimeMillis(); // proceed():執行連接點,返回連接點的返回值 // 獲取正在執行的連接點對象所在的類,打印結果:class org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint Class<? extends ProceedingJoinPoint> class1 = pjp.getClass(); //System.out.println("class:" + class1); // 當前執行的連接點,打印結果:int com.stu.impl.StuImpl.update(int,int) Signature signature = pjp.getSignature(); //System.out.println("signature:" + signature); // 連接點的方法名,打印結果:update String name = signature.getName(); //System.out.println("name:" + name); // 連接點所在的類,打印結果:class com.stu.impl.StuImpl Class declaringType = signature.getDeclaringType(); //System.out.println("declaringType:" + declaringType); // 連接點所在的類名全路徑,打印結果:com.stu.impl.StuImpl String declaringTypeName = signature.getDeclaringTypeName(); //System.out.println("declaringTypeName:" + declaringTypeName); // 調用連接點的目標對象,打印結果:com.stu.impl.StuImpl@6e4784bc Object target = pjp.getTarget(); //System.out.println("target:" + target); // 連接點傳遞的參數列表 Object[] args = pjp.getArgs(); System.out.println("args.length:" + args.length); for (Object o : args) {
System.out.println("arg:"+o);
} obj = pjp.proceed(); System.out.println("環繞后置通知"); } catch (Throwable e) { System.out.println("環繞異常通知"); Signature signature = pjp.getSignature(); System.out.println(signature.getDeclaringTypeName()+"."+signature.getName()+"方法時發生異常,異常的原因是" + e.getMessage()); } finally { System.out.println("環繞最終通知"); afterTime = System.currentTimeMillis(); Signature signature = pjp.getSignature(); System.out.println(signature.getDeclaringTypeName()+"."+signature.getName()+"方法執行了"+(afterTime-startTime)+"ms"); } return obj; } }
3.測試類
package com.stu; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.stu.impl.StuImpl; public class StuTest { public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); StuImpl stuimpl = context.getBean(StuImpl.class);
Object object = stuimpl.test(1, 2);
System.out.println("object的值"+o); } }
4.打印結果:使用環繞通知,異常后返回值0,使用Object接受返回值並輸出
環繞通知around
環繞前置通知
args.length:2
arg:1
arg:2
test方法
環繞后置通知
環繞最終通知
com.stu.impl.StuImpl.test方法執行了16ms
object的值1