Spring中的AOP 面向切面程式設計

2021-03-19 12:00:55

Spring中的AOP 面向切面程式設計

一,什麼是AOP
AOP(Aspect Oriented Programming)面向切面程式設計,是Spring框架中的內容,它是針對於一個事件的某個步驟或階段,主要應用於:紀錄檔,事務處理,例外處理等方面,它的原理是:通過過濾,對指定的一些操作直接新增設定好的方法,不需要頻繁的呼叫,在不使用介面的情況下實現java的動態代理。
AOP技術利用一種稱為「橫切」的技術,剖解開封裝物件的內部,將影響多個類的公共行為封裝到一個可重用的模組中,並將其命名為Aspect切面。所謂的切面,簡單來說就是與業務無關,卻為業務模組所共同呼叫的邏輯,將其封裝起來便於減少系統的重複程式碼,降低模組的耦合度,有利用未來的可操作性和可維護性。
利用AOP可以對業務邏輯各個部分進行隔離,從而使業務邏輯各部分之間的耦合度降低,提高程式的可重用性,同時提高開發效率。
Spring AOP 模組提供攔截器來攔截一個應用程式,例如,當執行一個方法時,你可以在方法執行之前或之後新增額外的功能。
二 AOP術語
在這裡插入圖片描述
三 通知的型別
Spring 方面可以使用下面提到的五種通知:
在這裡插入圖片描述
四 Spring 中基於AOP的XML架構
以銀行系統的存款和轉賬流程來說,其中都存在相同的驗證流程,AOP思想則是將這些相同的流程抽離出來,以存錢/轉賬方法為切入點,分別在此切入點之前或之後建立設定。
程式碼展示:
為了在本節的描述中使用 aop 名稱空間標籤,你需要匯入 spring-aop j架構,如下所述:

<?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.xsd
</beans>                         ">

首先建立存款和轉賬的介面

package cn.tb.dao;

public interface BankDao {
    //存錢
    public void saveMoney();

    //轉賬
    public void remirt();
}

然後設定相關流程
驗證事務

package cn.tb.impl;

public class AdminCheck {
    public void check(){
        System.out.println("許可權驗證開始");
    }
}

處理和提交事務

package cn.tb.impl;

import org.aspectj.lang.ProceedingJoinPoint;

public class TransactionManager {

    public void beginTransaction(){
        System.out.println("開始事務處理");
    }

    public void commitTrnasaction(){
        System.out.println("提交事務處理");
    }

    public void doInceptor(ProceedingJoinPoint point) throws Throwable{
        beginTransaction();
        point.proceed();
        commitTrnasaction();
    }
}

執行相關操作

package cn.tb.impl;

import cn.tb.dao.BankDao;

public class BankDaoImpl implements BankDao{
    @Override
    public void saveMoney() {
        System.out.println("正在存錢");
    }

    @Override
    public void remirt() {
        System.out.println("正在轉賬");
    }
}

紀錄檔寫入

package cn.tb.impl;

public class LogManager {
    //紀錄檔
    public void writeLog(){
        System.out.println("紀錄檔正在寫入");
    }
}

最後設定完整的Spring 中基於AOP的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"
       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.xsd
                           ">

    <!--注入bean-->
    <bean class="cn.tb.impl.AdminCheck" id="adminCheck"></bean>
    <bean class="cn.tb.impl.BankDaoImpl" id="bankDao"></bean>
    <bean class="cn.tb.impl.LogManager" id="logManager"></bean>
    <bean class="cn.tb.impl.TransactionManager" id="transactionManager"></bean>

    <!--開始spring aop 面向切面設定-->
    <aop:config>
        
        <!--切入點 什麼時機,什麼時候切入-->
        <aop:pointcut id="serviceInceptor" expression="execution(* cn.tb.impl.*.*(..))"></aop:pointcut>

        <!--前置通知 在一個方法執行之前,執行通知。-->
        <aop:aspect ref="adminCheck">
            <aop:before method="check" pointcut-ref="serviceInceptor"></aop:before>
        </aop:aspect>

        <!--環繞通知 在建議方法呼叫之前和之後,執行通知。-->
        <aop:aspect ref="transactionManager">
            <aop:around method="doInceptor" pointcut-ref="serviceInceptor"></aop:around>
        </aop:aspect>

        <!--後置通知 在一個方法執行之後,不考慮其結果,執行通知。-->
        <aop:aspect ref="logManager">
            <aop:after method="writeLog" pointcut-ref="serviceInceptor"></aop:after>
        </aop:aspect>
    </aop:config>
</beans>

測試

package cn.tb.test;

import cn.tb.dao.BankDao;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {
    public static void main(String[] args) {
        test1();
        System.out.println("-------------");
        test2();
    }
    //存錢
    private static void test1() {
        ApplicationContext alc = new ClassPathXmlApplicationContext("Spring.xml");
        BankDao dao = alc.getBean("bankDao", BankDao.class);
        dao.saveMoney();
    }
    //轉賬
    private static void test2() {
        ApplicationContext alc = new ClassPathXmlApplicationContext("Spring.xml");
        BankDao dao = alc.getBean("bankDao", BankDao.class);
        dao.remirt();
    }
}

測試結果:
在這裡插入圖片描述