Spring AOP及事務配置三種模式詳解

女友在高考發表於2021-11-17

Spring AOP簡述

Spring AOP的設計思想,就是通過動態代理,在執行期對需要使用的業務邏輯方法進行增強。

使用場景如:日誌列印、許可權、事務控制等。

預設情況下,Spring會根據被代理的物件是否實現介面來選擇使用JDK還是CGLIB。當被代理物件沒有實現介面時,Spring會選擇CGLIB。當實現了介面,Spring會選擇JDK官方的代理技術,不過我們也可以通過配置的方式,讓Spring強制使用CGLIB。

配置方式有兩種:

  • 使⽤aop:config標籤配置
<aop:config proxy-target-class="true">
  • 使⽤aop:aspectj-autoproxy標籤配置
<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-
autoproxy>

Spring中AOP的實現

2.1 XML模式

  1. 引入依賴(如果專案裡沒有的話)
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>5.1.12.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.4</version>
</dependency>
  1. xml配置

主要看下面的aop部分

<?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:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
       https://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/tx
       https://www.springframework.org/schema/tx/spring-tx.xsd
         http://www.springframework.org/schema/aop
       https://www.springframework.org/schema/aop/spring-aop.xsd
">

xml相關切面配置

<bean id="logUtil" class="com.mmc.ioc.utils.LogUtil"></bean>

    <!--aop的配置-->
       <!--aop的配置-->
    <aop:config>
        <!--配置切面-->
        <aop:aspect id="logAdvice" ref="logUtil">
            <aop:pointcut id="logAspect" expression="execution(public * com.mmc.ioc.service.impl.TransferServiceImpl.transfer(..))"></aop:pointcut>

            <!--前置通知-->
            <aop:before method="printLog" pointcut-ref="logAspect"></aop:before>
            <!--後置通知,無論業務是否正常執行-->
            <aop:after method="after" pointcut-ref="logAspect"></aop:after>
            <!--正常執行-->
            <aop:after-returning method="afterReturn" pointcut-ref="logAspect"></aop:after-returning>
            <!--異常執行-->
            <aop:after-throwing method="afterException" pointcut-ref="logAspect"></aop:after-throwing>
            <!--環繞通知-->
            <!--<aop:around method="around" pointcut-ref="logAspect" arg-names="proceedingJoinPoint"></aop:around>-->
        </aop:aspect>
    </aop:config>

環繞通知可以實現上面的4種通知,並且可以控制業務方法是否執行。通過如下程式碼控制:

 proceedingJoinPoint.proceed(proceedingJoinPoint.getArgs());
public class LogUtil {

    public void printLog(){
        System.out.println("列印日誌");
    }

    public void after(){
        System.out.println("後日志列印,不管業務是否正常");
    }

    public void afterReturn(){
        System.out.println("正常執行完畢列印日誌");
    }

    public void afterException(){
        System.out.println("異常執行列印日誌");
    }

    public void around(ProceedingJoinPoint proceedingJoinPoint){
        System.out.println("環繞前置");
        try {
            Object result = proceedingJoinPoint.proceed(proceedingJoinPoint.getArgs());
            System.out.println("環繞正常執行");
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            System.out.println("環繞異常執行");
        }
    }
}
  1. 切入點表示式

舉例:

public void
com.lagou.service.impl.TransferServiceImpl.updateAccountByCardNo(c
om.lagou.pojo.Account)
  • 訪問修飾符可以省略,也就是public可以不用寫
void com.mmc.ioc.service.impl.TransferServiceImpl.transfer(String,String,int)
  • 返回值可以用*代替,表示返回任意值
* com.mmc.ioc.service.impl.TransferServiceImpl.transfer(String,String,int)
  • 包名可以使用..表示當前包及其子包
* com..TransferServiceImpl.transfer(String,String,int)
  • 類名和方法名,都可以使用*表示任意類,任意方法
* com..*(String,String,int))
  • 引數列表,如果是基本型別可以直接寫名稱,如int。引用型別必須用全限定名稱
  • 引數列表可以使用*代替任意引數型別,但必須有引數
* com..*(*)
  • 引數列表可以使用..代替任意引數型別,有無引數均可
* com..*(*)
  • 全通配方式:
* *..*.*(..)

2.2 XML+註解模式

  1. XML中開啟Spring對註解AOP的支援
<!--開啟spring對註解aop的⽀持-->
<aop:aspectj-autoproxy/>
  1. 註解配置
@Component
@Aspect
public class LogUtil {

    @Pointcut("execution(* com.mmc.ioc.service.impl.TransferServiceImpl.transfer(..))")
    public void pointcut(){}

    @Before("pointcut()")
    public void printLog(){
        System.out.println("列印日誌");
    }

    @After("pointcut()")
    public void after(){
        System.out.println("後日志列印,不管業務是否正常");
    }

    @AfterReturning("pointcut()")
    public void afterReturn(){
        System.out.println("正常執行完畢列印日誌");
    }

    @AfterThrowing("pointcut()")
    public void afterException(){
        System.out.println("異常執行列印日誌");
    }

//    @Around("pointcut()")
    public void around(ProceedingJoinPoint proceedingJoinPoint){
        System.out.println("環繞前置");
        try {
            Object result = proceedingJoinPoint.proceed(proceedingJoinPoint.getArgs());
            System.out.println("環繞正常執行");
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            System.out.println("環繞異常執行");
        }
    }
}

2.3 純註解模式

只需要用註解@EnableAspectJAutoProxy替換掉

<aop:aspectj-autoproxy/>

Spring事務配置

也分為3種模式

3.1 XML模式

  1. 引入pom依賴
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.1.12.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.4</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.1.12.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-tx</artifactId>
    <version>5.1.12.RELEASE</version>
</dependency>
  1. xml配置
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <constructor-arg name="dataSource" ref="dataSource"></constructor-arg>
    </bean>
    <tx:advice id="txAdice" transaction-manager="transactionManager">
        <!--定製事務細節-->
        <tx:attributes>
            <tx:method name="*" read-only="false" propagation="REQUIRED" isolation="DEFAULT"/>
            <tx:method name="query*" read-only="true" propagation="SUPPORTS"></tx:method>
        </tx:attributes>
    </tx:advice>

    <!--事務衡器邏輯-->
    <aop:config>
        <aop:advisor advice-ref="txAdice" pointcut="execution(* com.mmc.ioc.service.impl.TransferServiceImpl.transfer(..))"></aop:advisor>
    </aop:config>

3.2 基於XML+註解

  1. xml配置:
 <!--spring宣告式事務配置-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <constructor-arg name="dataSource" ref="dataSource"></constructor-arg>
    </bean>
    
    <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
  1. 在類或方法上面新增@Transactional註解
@Transactional(readOnly = true,propagation = Propagation.SUPPORTS)

3.3 純註解

用@EnableTransactionManagement 註解替換掉

 <tx:annotation-driven transaction-
manager="transactionManager"/> 

即可

相關文章