先了解什麼是註解
註解
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可更加明晰其修飾的目標。
- CONSTRUCTOR:用於描述構造器
- FIELD:用於描述域
- LOCAL_VARIABLE:用於描述區域性變數
- METHOD:用於描述方法
- PACKAGE:用於描述包
- PARAMETER:用於描述引數
- TYPE:用於描述類、介面(包括註解型別) 或enum宣告
表示需要在什麼級別儲存該註釋資訊,用於描述註解的生命週期(即:被描述的註解在什麼範圍內有效)
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