18-spring學習-AOP深入操作
阿新 • • 發佈:2018-01-06
方法 execution throw mage context ons 定義 tostring 指定
範例:定義一個參數攔截
package com.Spring.aop; import org.springframework.stereotype.Component; @Component public class ServiceAspect { public void serviceBefore() { System.out.println("AOP切面執行日誌記錄操作"); } public void serviceBefore2(Object arg) { System.out.println("AOP切面執行增加前操作,參數="+arg); } public void serviceAfter() { System.out.println("AOP切面執行事務處理操作"); } }
配置也修改:
<aop:config> <!-- 定義程序的切入點 --> <aop:pointcut expression="execution(* com.Spring..*.*(..)))" id="pointcut"/> <!-- 這裏ref的對象是通過annotation配置@Component出來的, --> <!-- 定義面向方面的處理類 --> <aop:aspect ref="serviceAspect"> <aop:before method="serviceBefore2" pointcut-ref="pointcut"/> <aop:after method="serviceAfter" pointcut-ref="pointcut"/> </aop:aspect> </aop:config> <aop:aspectj-autoproxy proxy-target-class="true"/>
此時運行報錯。
此時serviceBefore2方法有參數了,就需要修改了。
範例:定義切入點表達式
這裏通過 and args() 和arg-names來指定要傳入操作前方法的參數。
<aop:config> <!-- 定義程序的切入點 --> <aop:pointcut expression="execution(* com.Spring..*.*(..)) and args(vo))" id="pointcut"/> <!-- 這裏ref的對象是通過annotation配置@Component出來的, --> <!-- 定義面向方面的處理類 --> <aop:aspect ref="serviceAspect"> <aop:before method="serviceBefore2" pointcut-ref="pointcut" arg-names="vo"/> <aop:after method="serviceAfter" pointcut="execution(* com.Spring..*.*(..)))"/> </aop:aspect> </aop:config> <aop:aspectj-autoproxy proxy-target-class="true"/>
運行結果:
因為after方法沒有參數,不能直接使用第一個定義的切入點,所以這裏after方法重新指定一個切入點,
而before是有參數的,直接使用第一個定義的切入點就行了。
除了操作之前攔截,也可以針對返回的結果進行攔截。
範例:針對返回結果攔截
package com.Spring.aop; import org.springframework.stereotype.Component; @Component public class ServiceAspect { public void serviceBefore() { System.out.println("AOP切面執行日誌記錄操作"); } public void serviceBefore2(Object arg) { System.out.println("AOP切面執行增加前操作,參數=" +arg); } public void serviceAfter() { System.out.println("AOP切面執行事務處理操作"); } public void serviceAfterReturn(Object val) //表示操作結果 { System.out.println("AOP切面操作完成,返回結果:"+val); } }
配置裏面修改:
<aop:config>
<!-- 定義程序的切入點 -->
<aop:pointcut expression="execution(* com.Spring..*.*(..)) and args(vo))" id="pointcut"/>
<!-- 這裏ref的對象是通過annotation配置@Component出來的, -->
<!-- 定義面向方面的處理類 -->
<aop:aspect ref="serviceAspect">
<aop:before method="serviceBefore2" pointcut-ref="pointcut" arg-names="vo"/>
<aop:after method="serviceAfter" pointcut="execution(* com.Spring..*.*(..)))"/>
<aop:after-returning method="serviceAfterReturn" pointcut="execution(* com.Spring..*.*(..)))" returning="haha" arg-names="haha"/>
</aop:aspect>
</aop:config>
這裏通過returning和arg-names來傳遞返回結果給操作完成後返回方法:serviceAfterReturn,做完這個方法的參數。
執行結果:
除了返回結果的攔截之外,還能進行異常處理的攔截操作。
範例:修改MemberServiceImpl
package com.Spring.Test; import org.apache.commons.lang.NullArgumentException; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.Spring.Service.IMemberService; import com.Spring.Service.Impl.MemberServiceImpl; import com.Spring.Vo.Member; public class TestMemberService { public static void main(String args[]) { throw new NullArgumentException("我來拋出一個異常"); /* ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml"); IMemberService ser=ctx.getBean("memberServiceImpl",MemberServiceImpl.class); Member vo=new Member(); vo.setMid("hello"); vo.setName("你好"); System.out.println(ser.insert(vo)); */ } }
增加攔截處理操作
package com.Spring.aop; import org.springframework.stereotype.Component; @Component public class ServiceAspect { public void serviceBefore() { System.out.println("AOP切面執行日誌記錄操作"); } public void serviceBefore2(Object arg) { System.out.println("AOP切面執行增加前操作,參數=" +arg); } public void serviceAfter() { System.out.println("AOP切面執行事務處理操作"); } public void serviceAfterReturn(Object val) //表示操作結果 { System.out.println("AOP切面操作完成,返回結果:"+val); } public void serviceAfterThrow(Exception e) //表示操作結果 { System.out.println("AOP切面操作出現異常:"+e); } }
配置:
<aop:config> <!-- 定義程序的切入點 --> <aop:pointcut expression="execution(* com.Spring..*.*(..)) and args(vo))" id="pointcut"/> <!-- 這裏ref的對象是通過annotation配置@Component出來的, --> <!-- 定義面向方面的處理類 --> <aop:aspect ref="serviceAspect"> <aop:before method="serviceBefore2" pointcut-ref="pointcut" arg-names="vo"/> <aop:after method="serviceAfter" pointcut="execution(* com.Spring..*.*(..)))"/> <aop:after-returning method="serviceAfterReturn" pointcut="execution(* com.Spring..*.*(..)))" returning="haha" arg-names="haha"/> <aop:after-throwing method="serviceAfterThrow" pointcut="execution(* com.Spring..*.*(..)))" arg-names="e" throwing="abc"/> </aop:aspect> </aop:config> <aop:aspectj-autoproxy proxy-target-class="true"/>
這裏因為需要傳遞異常參數,所以需要arg-names和throwing,但是這兩個的值隨便寫就像了,不用想對應起來。
運行結果:
以上幾個攔截器已經可以處理AOP可以處理的範疇。但是為了簡化,整個AOP還提供環繞通知,
即一個方法可以處理所有的aop操作,這種操作更像代理結構:
範例:增加環繞處理
但是必須考慮接收參數的情況,而接收的參數類型只能是一種類型:ProceedingJoinPoint,通過此類型可以取得全部的提交參數信息。
public Object serviceAround(ProceedingJoinPoint point) throws Throwable { System.out.println("AOP切面數據層方法調用之前,參數:"+Arrays.toString(point.getArgs())); Member vo=new Member(); vo.setMid("TestAOP"); vo.setName("測試AOP"); Object retVal=point.proceed(new Object[]{ vo }); //retVal接收方法數據層調用之後的結果 System.out.println("AOP切面數據層方法調用之後,返回值:"+retVal); return true; }
在整個環繞攔截之中,用戶可以任意修改傳遞的參數數據,也可以修改返回的結果。
配置環繞攔截:
<aop:around method="serviceAround" pointcut="execution(* com.Spring..*.*(..)))" />
執行結果:
所以,在所有AOP操作中,環繞的功能是最強大的。其他攔截只能做一些信息記錄,而環繞可以對傳入的參數和返回結果進行控制。
18-spring學習-AOP深入操作