1. 程式人生 > >18-spring學習-AOP深入操作

18-spring學習-AOP深入操作

方法 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深入操作