《四 spring原始碼》spring的事務註解@Transactional 原理分析

x號開發者發表於2019-03-28

先了解什麼是註解

註解

Jdk1.5新增新技術,註解。很多框架為了簡化程式碼,都會提供有些註解。可以理解為外掛,是程式碼級別的外掛,在類的方法上寫:@XXX,就是在程式碼上插入了一個外掛。

註解不會也不能影響程式碼的實際邏輯,僅僅起到輔助性的作用。

註解分類:內建註解(也成為元註解 jdk 自帶註解)自定義註解(Spring框架

什麼內建註解

1) @SuppressWarnings   再程式前面加上可以在javac編譯中去除警告--階段是SOURCE
2) @Deprecated   帶有標記的包,方法,欄位說明其過時----階段是SOURCE
3)@Overricle   打上這個標記說明該方法是將父類的方法重寫--階段是SOURCE

實現自定義註解

元註解的作用就是負責註解其他註解。Java5.0定義了4個標準的meta-annotation型別,它們被用來提供對其它 annotation型別作說明。Java5.0定義的元註解:
@Target

@Target說明了Annotation所修飾的物件範圍:Annotation可被用於 packages、types(類、介面、列舉、Annotation型別)、型別成員(方法、構造方法、成員變數、列舉值)、方法引數和本地變數(如迴圈變數、catch引數)。在Annotation型別的宣告中使用了target可更加明晰其修飾的目標。

  1. CONSTRUCTOR:用於描述構造器
  2. FIELD:用於描述域
  3. LOCAL_VARIABLE:用於描述區域性變數
  4. METHOD:用於描述方法
  5. PACKAGE:用於描述包
  6. PARAMETER:用於描述引數
  7. TYPE:用於描述類、介面(包括註解型別) 或enum宣告


2.@Retention

表示需要在什麼級別儲存該註釋資訊,用於描述註解的生命週期(即:被描述的註解在什麼範圍內有效)
3.@Documented
4.@interface 

@Target(value = { ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface AddAnnotation {

    int userId() default 0;

    String userName() default "預設名稱";

    String[]arrays();
}
反射讀取註解資訊
    public static void main(String[] args) throws ClassNotFoundException {
        Class classInfo = Class.forName("com.entity.User");
        // 獲取到所有方法
        Method[] methods = classInfo.getDeclaredMethods();
        for (Method method : methods) {
            System.out.println(method);
        //檢視該方法是否存在註解 AddAnnotation declaredAnnotation
= method.getDeclaredAnnotation(AddAnnotation.class); if (declaredAnnotation == null) { // 結束本次迴圈 continue; } // 獲取userId int userId = declaredAnnotation.userId(); System.out.println("userId:" + userId); // 獲取userName String userName = declaredAnnotation.userName(); System.out.println("userName:" + userName); // 獲取arrays String[] arrays = declaredAnnotation.arrays(); for (String str : arrays) { System.out.println("str:" + str); } } }

 

自定義事務註解

//程式設計事務(需要手動begin 手動回滾  手都提交)
@Component()
@Scope("prototype") // 設定成原型解決執行緒安全
public class TransactionUtils {

    private TransactionStatus transactionStatus;
    // 獲取事務源
    @Autowired
    private DataSourceTransactionManager dataSourceTransactionManager;

    // 開啟事務
    public TransactionStatus begin() {
        transactionStatus = dataSourceTransactionManager.getTransaction(new DefaultTransactionAttribute());
        return transactionStatus;
    }

    // 提交事務
    public void commit(TransactionStatus transaction) {
        dataSourceTransactionManager.commit(transaction);
    }

    // 回滾事務
    public void rollback() {
        System.out.println("rollback");
        dataSourceTransactionManager.rollback(transactionStatus);
    }

}

註解類

@Autowired
    private TransactionUtils transactionUtils;

    @AfterThrowing("execution(* com.itmayiedu.service.*.*.*(..))")
    public void afterThrowing() throws NoSuchMethodException, SecurityException {
        // isRollback(proceedingJoinPoint);
        System.out.println("程式發生異常");
        // TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        // TransactionStatus currentTransactionStatus =
        // TransactionAspectSupport.currentTransactionStatus();
        // System.out.println("currentTransactionStatus:" +
        // currentTransactionStatus);
        transactionUtils.rollback();
    }

    // // 環繞通知 在方法之前和之後處理事情
    @Around("execution(* com.itmayiedu.service.*.*.*(..))")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {

        // 呼叫方法之前執行
        TransactionStatus transactionStatus = begin(proceedingJoinPoint);
        proceedingJoinPoint.proceed();// 代理呼叫方法 注意點: 如果呼叫方法丟擲異常不會執行後面程式碼
        // 呼叫方法之後執行
        commit(transactionStatus);
    }

    public TransactionStatus begin(ProceedingJoinPoint pjp) throws NoSuchMethodException, SecurityException {

        // // 判斷是否有自定義事務註解
        ExtTransaction declaredAnnotation = getExtTransaction(pjp);
        if (declaredAnnotation == null) {
            return null;
        }
        // 如果有自定義事務註解,開啟事務
        System.out.println("開啟事務");
        TransactionStatus transactionStatu = transactionUtils.begin();
        return transactionStatu;
    }

    public void commit(TransactionStatus transactionStatu) {
        if (transactionStatu != null) {
            // 提交事務
            System.out.println("提交事務");
            transactionUtils.commit(transactionStatu);
        }
    }

    public ExtTransaction getExtTransaction(ProceedingJoinPoint pjp) throws NoSuchMethodException, SecurityException {
        // 獲取方法名稱
        String methodName = pjp.getSignature().getName();
        // 獲取目標物件
        Class<?> classTarget = pjp.getTarget().getClass();
        // 獲取目標物件型別
        Class<?>[] par = ((MethodSignature) pjp.getSignature()).getParameterTypes();
        // 獲取目標物件方法
        Method objMethod = classTarget.getMethod(methodName, par);
        // // 判斷是否有自定義事務註解
        ExtTransaction declaredAnnotation = objMethod.getDeclaredAnnotation(ExtTransaction.class);
        if (declaredAnnotation == null) {
            System.out.println("您的方法上,沒有加入註解!");
            return null;
        }
        return declaredAnnotation;

    }

    // 回滾事務
    public void isRollback(ProceedingJoinPoint pjp) throws NoSuchMethodException, SecurityException {
        // // 判斷是否有自定義事務註解
        ExtTransaction declaredAnnotation = getExtTransaction(pjp);
        if (declaredAnnotation != null) {
            System.out.println("已經開始回滾事務");
            // 獲取當前事務 直接回滾
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return;
        }
    }

使用自定義註解

@ExtTransaction
public void add() {
userDao.add("test001", 20);
int i = 1 / 0;
System.out.println("################");
userDao.add("test002", 21);
}

Spring事物傳播行為

Spring中事務的定義:

Propagation(key屬性確定代理應該給哪個方法增加事務行為。這樣的屬性最重要的部份是傳播行為。)有以下選項可供使用:

PROPAGATION_REQUIRED—如果當前有事務,就用當前事務,如果當前沒有事務,就新建一個事務。這是最常見的選擇。

PROPAGATION_SUPPORTS--支援當前事務,如果當前沒有事務,就以非事務方式執行。//如果外層方法沒有事務,就會以非事務進行執行。

PROPAGATION_MANDATORY--支援當前事務,如果當前沒有事務,就丟擲異常。 

PROPAGATION_REQUIRES_NEW--新建事務,如果當前存在事務,把當前事務掛起。 

PROPAGATION_NOT_SUPPORTED--以非事務方式執行操作,如果當前存在事務,就把當前事務掛起。

--- 如果當前有事務,就是以非事務進行執行

PROPAGATION_NEVER--以非事務方式執行,如果當前存在事務,則丟擲異常。

 

預設傳播行為為REQUIRED

相關文章