1. 程式人生 > >手寫spring事務(註解版本)

手寫spring事務(註解版本)

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()裡面有異常就走異常通知(回滾事務)