springmvc配置AOP的兩種方式


spingmvc配置AOP有兩種方式,一種是利用注解的方式配置,另一種是XML配置實現。

應用注解的方式配置:

先在maven中引入AOP用到的依賴

<dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>4.3.1.RELEASE</version>
    </dependency>
    <!-- aop aspect注解導包-->
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjrt</artifactId>
      <version>1.8.6</version>
    </dependency>
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.8.9</version>
    </dependency>

然后在springmvc的配置文件中加入AOP的配置,即掃描AOP的包以及讓AOP生效

<!-- AOP 注解方式 ;定義Aspect -->
    <!-- 激活組件掃描功能,在包"com.example.aop及其子包下面自動掃描通過注解配置的組件-->
    <context:component-scan base-package="com.example.aop"/>
    <!-- 啟動AspectJ支持   只對掃描過的bean有效-->
    <aop:aspectj-autoproxy proxy-target-class="true" />

然后加入AOP邏輯處理類

package com.example.aop;

import java.util.Arrays;
import java.util.List;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Aspect    //該標簽把LoggerAspect類聲明為一個切面
@Order(1)  //設置切面的優先級:如果有多個切面,可通過設置優先級控制切面的執行順序(數值越小,優先級越高)
@Component //該標簽把LoggerAspect類放到IOC容器中
public class LoggerAspect {

    /**
     * 定義一個方法,用於聲明切入點表達式,方法中一般不需要添加其他代碼
     * 使用@Pointcut聲明切入點表達式
     * 后面的通知直接使用方法名來引用當前的切點表達式;如果是其他類使用,加上包名即可
     */
    @Pointcut("execution(public * com.example.controller.*Controller.*(..))")
    public void declearJoinPointExpression(){}

    /**
     * 前置通知
     * @param joinPoint
     */
    @Before("declearJoinPointExpression()") //該標簽聲明次方法是一個前置通知:在目標方法開始之前執行
    public void beforMethod(JoinPoint joinPoint){
        String methodName = joinPoint.getSignature().getName();
        List<Object> args = Arrays.asList(joinPoint.getArgs());
        System.out.println("this method "+methodName+" begin. param<"+ args+">");
    }
    /**
     * 后置通知(無論方法是否發生異常都會執行,所以訪問不到方法的返回值)
     * @param joinPoint
     */
    @After("declearJoinPointExpression()")
    public void afterMethod(JoinPoint joinPoint){
        String methodName = joinPoint.getSignature().getName();
        System.out.println("this method "+methodName+" end.");
    }
    /**
     * 返回通知(在方法正常結束執行的代碼)
     * 返回通知可以訪問到方法的返回值!
     * @param joinPoint
     */
    @AfterReturning(value="declearJoinPointExpression()",returning="result")
    public void afterReturnMethod(JoinPoint joinPoint,Object result){
        String methodName = joinPoint.getSignature().getName();
        System.out.println("this method "+methodName+" end.result<"+result+">");
    }
    /**
     * 異常通知(方法發生異常執行的代碼)
     * 可以訪問到異常對象;且可以指定在出現特定異常時執行的代碼
     * @param joinPoint
     * @param ex
     */
    @AfterThrowing(value="declearJoinPointExpression()",throwing="ex")
    public void afterThrowingMethod(JoinPoint joinPoint,Exception ex){
        String methodName = joinPoint.getSignature().getName();
        System.out.println("this method "+methodName+" end.ex message<"+ex+">");
    }
    /**
     * 環繞通知(需要攜帶類型為ProceedingJoinPoint類型的參數)
     * 環繞通知包含前置、后置、返回、異常通知;ProceedingJoinPoin 類型的參數可以決定是否執行目標方法
     * 且環繞通知必須有返回值,返回值即目標方法的返回值
     * @param point
     */
    @Around(value="declearJoinPointExpression()")
    public Object aroundMethod(ProceedingJoinPoint point){

        Object result = null;
        String methodName = point.getSignature().getName();
        try {
            //前置通知
            System.out.println("The method "+ methodName+" start. param<"+ Arrays.asList(point.getArgs())+">");
            //執行目標方法
            result = point.proceed();
            //返回通知
            System.out.println("The method "+ methodName+" end. result<"+ result+">");
        } catch (Throwable e) {
            //異常通知
            System.out.println("this method "+methodName+" end.ex message<"+e+">");
            throw new RuntimeException(e);
        }
        //后置通知
        System.out.println("The method "+ methodName+" end.");
        return result;
    }
}

在類上加上注解Aspect聲明這個類是一個切面,加上component注解加入IOC容器中。Order注解是優先級,如果只有一個切面類可以不用。注解pointcut是聲明注解的作用范圍。execution(public * com.example.controller.*Controller.*(..))我這里用的execution表達式,代表作用com.example.controller包下所有以Controller結尾類的所有Public方法。@pointcut所描述的方法里面通常不需要內容。切面通知包含:

前置通知(@Before,在執行方法之前,參數為JoinPoint)

后置通知(@After,無論方法拋不拋異常都會執行,所以獲取不到方法的返回值。參數為JoinPoint)

返回通知(@AfterReturning,在方法正常結束后執行,可以獲取到方法的返回值。參數為JoinPoint和result(Object))

異常通知(@AfterThrowing,在方法拋出異常時執行,可以獲取到異常對象,且可以指定在出現特定異常時執行的代碼,參數為JoinPoint何Exception)

環繞通知(@Around,環繞通知需要攜帶的類型為ProceedingJoinPoint類型的參數, 環繞通知包含前置、后置、返回、異常通知;ProceedingJoinPoin 類型的參數可以決定是否執行目標方法,且環繞通知必須有返回值,返回值即目標方法的返回值)

應用XML方式配置

依賴的話,應該不用加入AOP注解的依賴。先定義一個類,作為切面類。

 

package com.example.aop;

import java.util.Arrays;
import java.util.List;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.stereotype.Component;

@Component //該標簽把LoggerAspect類放到IOC容器中
public class SysAspect {

    /**
     * 前置通知
     * @param joinPoint
     */
    public void beforMethod(JoinPoint joinPoint){
        String methodName = joinPoint.getSignature().getName();
        List<Object> args = Arrays.asList(joinPoint.getArgs());
        System.out.println("this method "+methodName+" begin. param<"+ args+">");
    }
    /**
     * 后置通知(無論方法是否發生異常都會執行,所以訪問不到方法的返回值)
     * @param joinPoint
     */
    public void afterMethod(JoinPoint joinPoint){
        String methodName = joinPoint.getSignature().getName();
        System.out.println("this method "+methodName+" end.");
    }
    /**
     * 返回通知(在方法正常結束執行的代碼)
     * 返回通知可以訪問到方法的返回值!
     * @param joinPoint
     */
    public void afterReturnMethod(JoinPoint joinPoint,Object result){
        String methodName = joinPoint.getSignature().getName();
        System.out.println("this method "+methodName+" end.result<"+result+">");
    }
    /**
     * 異常通知(方法發生異常執行的代碼)
     * 可以訪問到異常對象;且可以指定在出現特定異常時執行的代碼
     * @param joinPoint
     * @param ex
     */
    public void afterThrowingMethod(JoinPoint joinPoint,Exception ex){
        String methodName = joinPoint.getSignature().getName();
        System.out.println("this method "+methodName+" end.ex message<"+ex+">");
    }
    /**
     * 環繞通知(需要攜帶類型為ProceedingJoinPoint類型的參數)
     * 環繞通知包含前置、后置、返回、異常通知;ProceedingJoinPoin 類型的參數可以決定是否執行目標方法
     * 且環繞通知必須有返回值,返回值即目標方法的返回值
     * @param point
     */
    public Object aroundMethod(ProceedingJoinPoint point){

        Object result = null;
        String methodName = point.getSignature().getName();
        try {
            //前置通知
            System.out.println("The method "+ methodName+" start. param<"+ Arrays.asList(point.getArgs())+">");
            //執行目標方法
            result = point.proceed();
            //返回通知
            System.out.println("The method "+ methodName+" end. result<"+ result+">");
        } catch (Throwable e) {
            //異常通知
            System.out.println("this method "+methodName+" end.ex message<"+e+">");
            throw new RuntimeException(e);
        }
        //后置通知
        System.out.println("The method "+ methodName+" end.");
        return result;
    }
}

 

可以看到,這個類除了沒有@Aspect以及相關切面的注解外,跟正常的AOP切面類沒有差別。如果聲明其讓其為一個切面。需要我們在xml文件中手動配置。

<!-- 配置切面的Bean -->
    <bean id="sysAspect" class="com.example.aop.SysAspect"/>
    <!-- 配置AOP -->
    <aop:config>
        <!-- 配置切點表達式  -->
        <aop:pointcut id="pointcut" expression="execution(public * com.example.controller.*Controller.*(..))"/>
        <!-- 配置切面及配置 -->
        <aop:aspect order="3" ref="sysAspect">
            <!-- 前置通知 -->
            <aop:before method="beforMethod"  pointcut-ref="pointcut" />
            <!-- 后置通知 -->
            <aop:after method="afterMethod"  pointcut-ref="pointcut"/>
            <!-- 返回通知 -->
            <aop:after-returning method="afterReturnMethod" pointcut-ref="pointcut" returning="result"/>
            <!-- 異常通知 -->
            <aop:after-throwing method="afterThrowingMethod" pointcut-ref="pointcut" throwing="ex"/>
            <aop:around method="aroundMethod" pointcut-ref="pointcut"/>
        </aop:aspect>
    </aop:config>

定義的切面bean就是我們自定義的切面類,然后配置AOP(<aop:config>)。先定義切面范圍pointcut。余下的就是制定aop的切面類、優先級然后再詳細配置切面的通知。這樣就跟注解的方式產生的效果一致了。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM