1. 程式人生 > >Spring全家桶(八)AOP核心思想與AspectJ 5種類型通知

Spring全家桶(八)AOP核心思想與AspectJ 5種類型通知

一、AOP核心思想

AOP是Aspect-Oriented Programming的縮寫,翻譯為面向切面程式設計。我個人理解切面就是一個方面。
例子,一個接口裡面有增刪改查四個方法:

package com.stuspring.aop.impl;

/**
 * Created by bee on 17/5/15.
 */
public interface ArithmeticCalculator {
     int add(int i,int j);
     int sub(int i,int j);
     int mul(int i,int j);
     int div(int
i,int j); }

實現類:

package com.stuspring.aop.impl;

import org.springframework.stereotype.Component;

/**
 * Created by bee on 17/5/15.
 */
@Component("arithmeticCalculator")
public class ArithmeticCalculatorImpl implements ArithmeticCalculator {
    @Override
    public int add(int i, int j) {
        int
result=i+j; return result; } @Override public int sub(int i, int j) { int result=i-j; return result; } @Override public int mul(int i, int j) { int result=i*j; return result; } @Override public int div(int i, int j) { int
result=i/j; return result; } }

如果想給這四個方法分別加上前置日誌功能,以其中一個為例,add方法變這樣:

  @Override
    public int add(int i, int j) {
        System.out.println("The method add begins with " +i+","+j);
        int result=i+j;
        return result;
    }

手動給每個方法都加上固然可行,但是維護起來過於麻煩,面向切面程式設計就是為了解決這一問題。AOP的好處就是每個邏輯位於一個位置,程式碼不分散便於維護和升級,業務模組更簡潔。

加一個日誌切面:

package com.stuspring.aop.impl;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

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

/**
 * Created by bee on 17/5/15.
 */

@Aspect
@Component
public class LoggingAspect {

    /**
     * 前置通知 方法開始之前執行
     * @param joinPoint
     */
    @Before("execution(public int com.stuspring.aop.impl.ArithmeticCalculatorImpl.*(int,int))")
    public void beforeMethod(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        List<Object> agrs = Arrays.asList(joinPoint.getArgs());
        System.out.println("The method " + methodName + " begins with " + agrs);
    }

    /**
     * 後置通知,方法執行完之後執行,不論方法是否出現異常
     * 後置通知中不能訪問目標方法的執行結果
     */
    @After("execution(public int com.stuspring.aop.impl.ArithmeticCalculatorImpl.*(int,int))")
    public void afterMethod(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        List<Object> args = Arrays.asList(joinPoint.getArgs());
        System.out.println("The method " + methodName + " ends with " + args);
    }
}

新建spring配置檔案beans-aspect.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:content="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context-4.3.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">

    <content:component-scan base-package="com.stuspring.aop.impl"/>
    <aop:aspectj-autoproxy/>
</beans>

附maven依賴:

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.3.8.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>4.3.8.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>4.3.8.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>4.3.8.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.8.10</version>
        </dependency>

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.10</version>
        </dependency>

二、五種型別通知

  1. @Before前置通知:方法開始之前執行。

     /**
         * 前置通知 方法開始之前執行
         * @param joinPoint
         */
        @Before("execution(public int com.stuspring.aop.impl.ArithmeticCalculatorImpl.*(int,int))")
        public void beforeMethod(JoinPoint joinPoint) {
            String methodName = joinPoint.getSignature().getName();
            List<Object> agrs = Arrays.asList(joinPoint.getArgs());
            System.out.println("The method " + methodName + " begins with " + agrs);
        }
  2. @After後置通知:方法開始之後執行,不論方法是否出現異常。

       /**
         * 後置通知,方法執行完之後執行,不論方法是否出現異常
         * 後置通知中不能訪問目標方法的執行結果
         */
        @After("execution(public int com.stuspring.aop.impl.ArithmeticCalculatorImpl.*(int,int))")
        public void afterMethod(JoinPoint joinPoint) {
            String methodName = joinPoint.getSignature().getName();
            List<Object> args = Arrays.asList(joinPoint.getArgs());
            System.out.println("The method " + methodName + " ends with " + args);
        }
  3. @AfterRunning:返回通知,在方法返回結果之後執行。

        /**
         * 返回通知,在方法正常結束之後執行的程式碼
         * 返回通知可以訪問方法的返回值
         */
    
        @AfterReturning(value="execution(public int com.stuspring.aop.impl.ArithmeticCalculatorImpl.*(int,int))",returning = "result")
        public void afterReturning(JoinPoint joinPoint,Object result){
    
            String methodName=joinPoint.getSignature().getName();
            System.out.println("The method "+methodName+" ends with "+result);
        }
  4. @AfterThrowing:異常通知,在方法丟擲異常之後。

        /**
         * 異常通知:在方法丟擲異常之後執行
         * @param joinPoint
         * @param e
         */
    
        @AfterThrowing(value="execution(public int com.stuspring.aop.impl.ArithmeticCalculatorImpl.*(int,int))",throwing = "e")
        public void afterThrowing(JoinPoint joinPoint,Exception e){
            String methodName=joinPoint.getSignature().getName();
            System.out.println("The method "+methodName+" occurs execution: "+e);
        }
  5. @Around:環繞通知,圍繞方法執行。

        /**
         * 環繞通知需要攜帶ProceedingJoinPoint型別的引數
         * 環繞通知類似於動態代理的全過程:ProceedingJoinPoint型別的引數可以決定是否執行目標方法
         * 環繞通知必須有返回值,返回值即為目標方法的返回值
         *
         * @param pjd
         */
        @Around("execution(public int com.stuspring.aop.impl.ArithmeticCalculatorImpl.*(..))")
        public Object aroundMethod(ProceedingJoinPoint pjd) {
    
            Object result = null;
            String methodName = pjd.getSignature().getName();
    
            try {
                //前置通知
                System.out.println("--->The method " + methodName + " begins with " + Arrays.asList(pjd.getArgs()));
                //執行目標方法
                result = pjd.proceed();
                //後置通知
                System.out.println("--->The method " + methodName + " ends with " + result);
    
            } catch (Throwable e) {
                //異常通知
                System.out.println("The method "+methodName+" occurs exception : "+e);
            }
    
            //後置通知
            System.out.println("The Method "+methodName+" ends!");
            return result;
        }

三、指定切面的優先順序

切面的優先順序可以用@Order註解指定,傳入的整數值越小,優先順序越高。
這裡寫圖片描述

四、複用切點表示式

   /**
     *  定義一個方法用於宣告切入點表示式。一般地,該方法不需要再寫其它程式碼。
     */
    @Pointcut("execution(public int com.stuspring.aop.impl.ArithmeticCalculatorImpl.*(int,int))")
    public void declareJoinPointExpression(){
    }
    /**
     * 前置通知 方法開始之前執行
     * @param joinPoint
     */

    @Before("declareJoinPointExpression()")
    public void beforeMethod(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        List<Object> agrs = Arrays.asList(joinPoint.getArgs());
        System.out.println("The method " + methodName + " begins with " + agrs);
    }

外部類引用可以使用報名加方法名的方法。

五、配置檔案方式配置AOP

介面:

package com.stuspring.aop.fileimpl;

/**
 * Created by bee on 17/5/16.
 */
public interface ArithmeticCalculator {
    int add(int i,int j);
    int sub(int i,int j);
    int mul(int i,int j);
    int div(int i,int j);
}

實現類:

package com.stuspring.aop.fileimpl;

/**
 * Created by bee on 17/5/16.
 */
public class ArithmeticCalculatorImpl implements ArithmeticCalculator {
    @Override
    public int add(int i, int j) {
        int result=i+j;
        return result;
    }

    @Override
    public int sub(int i, int j) {
        int result=i-j;
        return result;
    }

    @Override
    public int mul(int i, int j) {
        int result=i*j;
        return result;
    }

    @Override
    public int div(int i, int j) {
        int result=i/j;
        return result;
    }
}

日誌切面:

package com.stuspring.aop.fileimpl;

import org.aspectj.lang.JoinPoint;

/**
 * Created by bee on 17/5/16.
 */
public class LoggingAspect {

    public void beforeMethod(JoinPoint joinPoint){
        String methodName=joinPoint.getSignature().getName();
        System.out.println("The method begins with "+methodName);
    }
}

引數驗證切面:

package com.stuspring.aop.fileimpl;

import org.aspectj.lang.JoinPoint;

/**
 * Created by bee on 17/5/16.
 */
public class ValidationAspect {

    public void validateArgs(JoinPoint joinPoint){
        System.out.println("validationMethod......");
    }
}

Spring配置檔案:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">

    <!--配置bean-->
    <bean id="arithmeticCalculator" class="com.stuspring.aop.fileimpl.ArithmeticCalculatorImpl"/>
    <bean id="loggingAspect" class="com.stuspring.aop.fileimpl.LoggingAspect"/>
    <bean id="validationAspect" class="com.stuspring.aop.fileimpl.ValidationAspect"/>

    <aop:config>
        <!--配置切面表示式-->
        <aop:pointcut id="pointcut" expression="execution(public int com.stuspring.aop.fileimpl.ArithmeticCalculatorImpl.*(int,int))"/>
        <!--配置切面通知-->
        <aop:aspect ref="loggingAspect" order="2">
            <aop:before method="beforeMethod" pointcut-ref="pointcut"/>
        </aop:aspect>

        <aop:aspect ref="validationAspect" order="1">
            <aop:before method="validateArgs" pointcut-ref="pointcut"/>
        </aop:aspect>

    </aop:config>
</beans>

Main測試方法:

package com.stuspring.aop.fileimpl;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Created by bee on 17/5/16.
 */
public class Main {

    public static void main(String[] args) {
        ApplicationContext ctx=new ClassPathXmlApplicationContext("beans-aspectfile.xml");
        ArithmeticCalculator calculator= (ArithmeticCalculator) ctx.getBean("arithmeticCalculator");
        System.out.println(calculator.add(2,4));
    }
}

相關推薦

Spring全家()AOP核心思想AspectJ 5種類通知

一、AOP核心思想 AOP是Aspect-Oriented Programming的縮寫,翻譯為面向切面程式設計。我個人理解切面就是一個方面。 例子,一個接口裡面有增刪改查四個方法: package com.stuspring.aop.impl; /

Spring——AOP核心思想實現

AOP(Aspect Oriented Programming):面向切面程式設計 核心思想:動態的新增和刪除切面上的邏輯而不影響原來的執行程式碼 AOP相關概念: 1.JoinPoint 連線點,加入切面邏輯的位置。 @Before("exe

Spring全家系列--SpringBootMybatis結合

Mybatis 是一個持久層ORM框架,負責Java與資料庫資料互動,也可以簡易理解為中介,相對於它,還有個中介是hibernate,不過在mybatis中sql語句的靈活性,可優化性比較強,這也是現在大多數人選擇的原因。 mapper.xml、dao介面、實體類自動生成 下

Spring全家系列–SpringBoot之AOP詳解

//本文作者:cuifuan //本文將收錄到選單欄:《Spring全家桶》專欄中 面向方面程式設計(AOP)通過提供另一種思考程式結構的方式來補充面向物件程式設計(OOP)。 OOP中模組化的關鍵單元是類,而在AOP中,模組化單元是方面。 準備工作 首先,使用AOP要在bu

Spring全家系列一一SpringBootMybatis結合

本文首發於"Java知音"。 Mybatis 是一個持久層ORM框架,負責Java與資料庫資料互動,也可以簡易理解為中介,相對於它,還有個中介是hibernate,不過在mybatis中sql語句的靈活性,可優化性比較強,這也是現在大多數人選擇的原因。 1. mapper.

Spring全家系列–SpringBootMybatis結合

//本文作者:cuifuan Mybatis 是一個持久層ORM框架,負責Java與資料庫資料互動,也可以簡易理解為中介,相對於它,還有個中介是hibernate,不過在mybatis中sql語句的靈活性,可優化性比較強,這也是現在大多數人選擇的原因。 1. mapper.xml、dao介面、實體類自動生

Spring設計思想AOP設計思想原理(圖文並茂) 侵立刪

轉自:https://mp.weixin.qq.com/s/1p2XSfhM1V5CcWro6PZEwQ   前言   Spring 提供了AOP(Aspect Oriented Programming) 的支援, 那麼,什麼是AOP呢?本文將通過一個另外一個角度

正式開始瞭解和學習Spring全家 ——— 開始工作中的學習生涯

正式開始瞭解和學習Spring全家桶 ——— 開始工作中的學習生涯 前言 1. 對自己的時間沒有明確的計劃,導致沒有學習動力 2. 對自己的學習方向和起點沒有準確的定位 3. 對個人能力的判斷不準確

Spring全家帶來雲時代的軟體開發變革

快速發展和變化的業務需求所帶來的挑戰正在驅動現代企業數字化轉型,雲原生應用系統的構建是其中最為重要環節之一。 目前,雲原生應用開發框架Spring(包括Spring MVC、Spring Boot、Spring Cloud、Spring Cloud Dataflow)已經佔據Java軟體開發框架的統治地

Spring全家帶來雲時代的軟件開發變革

現象 ont for 總結 公有 最新 集成 RoCE 管理方式 快速發展和變化的業務需求所帶來的挑戰正在驅動現代企業數字化轉型,雲原生應用系統的構建是其中最為重要環節之一。 目前,雲原生應用開發框架Spring(包括Spring MVC、Spring Boot、Spri

Spring全家系列–[SpringBoot入門到跑路]

//本文作者:cuifuan Spring全家桶————[SpringBoot入門到跑路] 對於之前的Spring框架的使用,各種配置檔案XML、properties一旦出錯之後錯誤難尋,這也是為什麼SpringBoot被推上主流的原因,SpringBoot的配置簡單,說5分鐘能從框

SELinux安全模型的核心思想三種工作模式

enforce 權限 永久 iss linux社區 ive con 生產 調試 什麽是SELinux?在內核2.6版本之前Linux的安全模型叫DAC(Discretionary Access Contorl,即自主訪問控制)。DAC的核心思想:進程想要訪問某資源,只需要擁

Spring全家系列——[SpringBoot漸入佳境]

Spring全家桶系列——[SpringBoot漸入佳境] //本文作者:cuifuan 萌新:小哥,我在實體類寫了那麼多get/set方法,看著很迷茫 小哥:那不是可以自動生成嗎? 萌新:雖然可以自動生成,但是如果我要修改某個變數的資料型別,我豈不是還要去修改get/set

Spring全家————[SpringBoot入門到跑路]

本文首發於“Java知音” 對於之前的Spring框架的使用,各種配置檔案XML、properties一旦出錯之後錯誤難尋,這也是為什麼SpringBoot被推上主流的原因,SpringBoot的配置簡單,說5分鐘能從框架的搭建到執行也不為過,現在更是微服務當道,所

Spring全家系列–SpringBoot漸入佳境

1.Lombok外掛 對於開發人員來說,我要解釋這個什麼意思,你肯定也是一知半解,直接來程式碼解釋吧 歡迎工作一到八年的Java工程師朋友們加入Java高階交流群:854630135 本群提供免費的學習指導 架構資料 以及免費的解答 不懂得問題都可以在本群提出來 之後還會有直播平臺和

Spring全家系列–「SpringBoot入門到跑路」

Spring全家桶————[SpringBoot入門到跑路] 對於之前的Spring框架的使用,各種配置檔案XML、properties一旦出錯之後錯誤難尋,這也是為什麼SpringBoot被推上主流的原因,SpringBoot的配置簡單,說5分鐘能從框架的搭建到執行也不為過,現在更是微

Spring全家–SpringBoot Rest API

  Spring Boot通過提供開箱即用的預設依賴或者轉換來補充Spring REST支援。在Spring Boot中編寫RESTful服務與SpringMVC沒有什麼不同。總而言之,基於Spring Boot的REST服務與基於Spring的REST服務完全相同,只是在我們引導底層應用程式的方式

Spring全家系列–SpringBoot之入門JPA

Spring全家桶系列–SpringBoot之入門JPA 什麼是JPA? 一種規範,並非ORM框架,也就是ORM上統一的規範 用了之後可以做什麼,為什麼要用? 程式碼解釋: 實體類 dao層 測試類 上面的操作已經完成了一個查詢全部,

《深入理解Spark-核心思想源碼分析》(二)第二章Spark設計理念和基本架構

基礎知識 cut info 負責 驅動 源碼分析 spa spark 節點 若夫乘天地之正,而禦六氣之辯解,以遊無窮者,彼且惡乎待哉?

《深入理解Spark:核心思想原始碼分析》(第2章)

《深入理解Spark:核心思想與原始碼分析》一書第一章的內容請看連結《第1章 環境準備》 本文主要展示本書的第2章內容: Spark設計理念與基本架構 “若夫乘天地之正,而御六氣之辯,以遊無窮者,彼且惡乎待哉?” ——《莊子·逍遙遊》 n本章導讀: 上一章,介紹了Spark環境的搭建,為方便讀