手寫spring事務(註解版本)
阿新 • • 發佈:2018-11-10
1.首先自定義一個事務註解(類似於@Transactional)
package com.itmayiedu.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; //事務註解 設定傳播行為 @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface ExtTransaction { }
3.編寫切面類AopExtTransaction.java
package com.itmayiedu.aop; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.interceptor.TransactionAspectSupport; import com.itmayiedu.annotation.ExtTransaction; import com.itmayiedu.transaction.TransactionUtils; @Component @Aspect//自定義事務註解具體實現 public class AopExtTransaction { @Autowired// 一個事務例項 針對一個事務,所以要在TransactionUtils上加Scope(value="prototype") private TransactionUtils transactionUtils; @AfterThrowing("execution(* com.itmayiedu.service.*.*.*(..))") public void afterThrowing(){ // 獲取當前事務進行回滾 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); } @Around("execution(* com.itmayiedu.service.*.*.*(..))") public void around(ProceedingJoinPoint pjp) throws Throwable{ // 1.獲取該方法上是否加上註解 ExtTransaction extTransaction = getMethodExtTransaction(pjp); TransactionStatus transactionStatus = begin(extTransaction); // 2.呼叫目標代理物件方法 pjp.proceed(); commit(transactionStatus); } private void commit(TransactionStatus transactionStatus) { // 5.如果存在註解,提交事務 if(transactionStatus!=null){ transactionUtils.commit(transactionStatus); } } private TransactionStatus begin(ExtTransaction extTransaction) { if(extTransaction==null){ return null; } // 2.如果存在事務註解,開啟事務 return transactionUtils.begin(); } // 獲取方法上是否存在事務註解 private ExtTransaction getMethodExtTransaction(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); Annotation[] declaredAnnotations = objMethod.getDeclaredAnnotations(); ExtTransaction extTransaction=(ExtTransaction) declaredAnnotations[0]; return extTransaction; } }
3.UserServiceImpl.java
package com.itmayiedu.service.impl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.interceptor.TransactionAspectSupport; import com.itmayiedu.annotation.ExtTransaction; import com.itmayiedu.dao.UserDao; import com.itmayiedu.service.UserService; import com.itmayiedu.transaction.TransactionUtils; @Service public class UserServiceImpl implements UserService{ @Autowired private UserDao userDao; @Autowired private TransactionUtils transactionUtils; @ExtTransaction public void add() { // 呼叫介面的時候 介面失敗 需要回滾,但是日誌記錄不需要回滾。 //logService.addLog(); // 後面程式發生錯誤,不能影響到我的回滾### 正常當addLog方法執行完畢,就應該提交事務 userDao.add("test001", 20); int i = 1 / 0; System.out.println("################"); userDao.add("test002", 21); } }
4.編寫測試類Test01.java
package com.itmayiedu.service;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test01 {
public static void main(String[] args) {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
UserService userService = (UserService) applicationContext.getBean("userServiceImpl");
userService.add();
}
}
解析:在走useService.add()之前被aop攔截,先走環繞通知(開啟事務,提交事務),如果useService.add()裡面有異常就走異常通知(回滾事務)