自定义注解简单实现
package com.learn.annotation;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;// 事務(wù)注解 設(shè)置傳播行為
/*** 在前面加個(gè)Ext* 這個(gè)注解是干嘛的* 你們一定要知道* 它是事務(wù)注解* 定義好了之后* 在這里面其實(shí)有這幾個(gè)方法* 但是我今天可能用不到這幾個(gè)方法* 你們下去自己去封裝* 設(shè)置傳播行為* 具體怎么實(shí)現(xiàn)呢* 方法我就不寫了* 你們自己寫* 我們看看源碼里面是怎么寫的* 你們看一下* 源碼里面加了攔截權(quán)限* 把這些我們也copy過來* 因?yàn)檫@個(gè)代碼你們看的懂* { ElementType.METHOD, ElementType.TYPE }* 我們可以寫這兩個(gè)* 可以在方法上面加上這個(gè)注解* 可以在類上加上這個(gè)注解* 我們不允許在類上用* 我們這個(gè)注解不允許在類上面用* 只允許在方法上去玩了* @Retention(RetentionPolicy.RUNTIME)* 這個(gè)寫完之后我們再寫第二步* 跟著我的步驟來* 封裝手動(dòng)事務(wù)* 這個(gè)是我昨天寫過的* 是不是這樣的* 我寫過的話就不寫了* 因?yàn)榇龝覀兙蜁玫竭@段代碼的* * * * @author Leon.Sun**/
@Target({ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface ExtTransaction {}
package com.learn.transaction;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Component;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.interceptor.DefaultTransactionAttribute;// 編程事務(wù)(需要手動(dòng)begin 手動(dòng)回滾 手都提交)
/*** 我們還原成昨天的* 否則到時(shí)會繞的* 這個(gè)是手動(dòng)獲取事務(wù)* 手動(dòng)begin* 手動(dòng)commit和手動(dòng)rollback* 這代碼你們有沒有印象* 昨天講過的* 我特意講過這段代碼的* 還手寫過這個(gè)事務(wù)的* 是不是這樣的* 這個(gè)代碼看不看得懂* 這個(gè)代碼不難* 只要?jiǎng)e人調(diào)用begin方法我就去開啟一個(gè)事務(wù)* 如果要是調(diào)用commit和rollback* 去回滾或者提交* 現(xiàn)在看應(yīng)該能夠看得懂* 這個(gè)昨天已經(jīng)講過的* 這個(gè)其實(shí)沒有什么難的* 你們學(xué)過事務(wù)都知道的* 然后我們接著再怎么做呢* 我們核心是在具體如何掃包* 具體如何掃包的話* 那么這里面我不是要寫一個(gè)AOP了* * * * @author Leon.Sun**/
@Component
//@Scope("prototype") // 每個(gè)事務(wù)都是新的實(shí)例 目的解決線程安全問題 多例子
public class TransactionUtils {// 全局接受事務(wù)狀態(tài)private TransactionStatus transactionStatus;// 獲取事務(wù)源@Autowiredprivate DataSourceTransactionManager dataSourceTransactionManager;// 開啟事務(wù)public TransactionStatus begin() {transactionStatus = dataSourceTransactionManager.getTransaction(new DefaultTransactionAttribute());return transactionStatus;}// 提交事務(wù)public void commit(TransactionStatus transaction) {dataSourceTransactionManager.commit(transaction);}// 回滾事務(wù)public void rollback() {dataSourceTransactionManager.rollback(transactionStatus);}}
package com.learn.aop;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 com.learn.annotation.ExtTransaction;
import com.learn.transaction.TransactionUtils;// 自定義事務(wù)注解具體實(shí)現(xiàn)
/*** 我們自定義的事務(wù)注解具體實(shí)現(xiàn)* 然后在這里寫一下* 加上切面編程@Aspect* 在這里面怎么寫呢* 在這里還要加上@Component* 讓他注入到Spring的容器里面去* 這步寫完了之后* 我說過的* 你們說一下這是一個(gè)什么通知啊* 就是這個(gè)攔截方法的時(shí)候* 攔截所有方法的情況下* 什么通知* 你們想一想* 就是這步他能用什么通知* 肯定是環(huán)繞通知* 記住肯定是環(huán)繞通知* 不可能用到其他通知的* 肯定是用環(huán)繞* 那我把環(huán)繞代碼copy過來好吧* 我就不去寫了* 因?yàn)槲易蛱熘v過了* 是不是這樣的* 再寫的話就比較浪費(fèi)時(shí)間了* 在這邊說一下* * * * @author Leon.Sun**/
@Aspect
@Component
public class AopExtTransaction {// 一個(gè)事務(wù)實(shí)例子 針對一個(gè)事務(wù)/*** 我們把自定義的手動(dòng)事務(wù)copy過來* 再去@Autowired一下* */@Autowiredprivate TransactionUtils transactionUtils;// 使用異常通知進(jìn)行 回滾事務(wù)/*** 我們現(xiàn)在是寫框架的話* 把它寫成全部的* "execution(* com.learn.service.*.*.*(..))"* 這是我要和你們?nèi)ブv一下的* 全部怎么寫* service.*.*.*(..)* 這個(gè)都理解吧* 我就不去說了* 我們找那個(gè)包下面的呢* 我們找這個(gè)包下面的* com.learn.service* 這步寫完了之后* 這邊的代碼就有點(diǎn)麻煩了* 怎么麻煩了* 這也是非常核心的代碼* * */@AfterThrowing("execution(* com.learn.service.*.*.*(..))")public void afterThrowing() {// 獲取當(dāng)前事務(wù)進(jìn)行回滾// TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();transactionUtils.rollback();}// 環(huán)繞通知 在方法之前和之后處理事情/*** 我們把這段代碼copy過來* 攔截到方法之后你們說一下* 我這邊就直接口說這個(gè)步驟* 步驟答出來可能會好理解點(diǎn)* 要不然直接這樣改的話可能會比較繞* 首先獲取到代理對象的方法* 第二步干嘛呢* 獲取該方法上是否加上注解* 是不是這樣的* 然后到第三步的時(shí)候* 你們想想到第三步怎么做* 如果存在事務(wù)注解* 是不是開啟這個(gè)事務(wù)* 然后到第四步干嘛* 調(diào)用目標(biāo)代理對象方法* 到第五步怎么做你想想* 第五步的時(shí)候代理對象方法調(diào)用完畢的情況下* 他怎么做* 想想怎么做* 判斷該方法上是否加上注解* 這個(gè)我昨天已經(jīng)說過了* 然后同樣道理* 第六步什么樣的呢* 如果存在注解* 你看我是寫的非常詳細(xì)的* 如果存在注解* 怎么樣呢* 是不是提交事務(wù)* 我們可以先把四步先寫出來* 獲取目標(biāo)代理方法這個(gè)比較麻煩* 大家寫的時(shí)候可以直接去copy* 因?yàn)檫@里面的代碼可能會比較多* 然后你們不要看我們文檔里面的* 有些方法沒有必要記下來* 你只要知道怎么做就行了* 這是我要和你們說的* 所以這邊我和你們說一下* 這個(gè)你們不要去記* * * * * @param pjp* @throws Throwable*/@Around("execution(* com.learn.service.*.*.*(..))")public void around(ProceedingJoinPoint pjp) throws Throwable {// 1.獲取該方法上是否加上注解ExtTransaction extTransaction = getMethodExtTransaction(pjp);/*** 我們拿到事務(wù)注解之后呢* */TransactionStatus transactionStatus = begin(extTransaction);// 2.調(diào)用目標(biāo)代理對象方法/*** 這個(gè)方法直接調(diào)用目標(biāo)代理對象* 待會我們的代碼都會做重構(gòu)* */pjp.proceed();// 3.判斷該方法上是否就上注解commit(transactionStatus);}private TransactionStatus begin(ExtTransaction extTransaction) {if (extTransaction == null) {return null;}// 2.如果存在事務(wù)注解,開啟事務(wù)/*** 開啟事務(wù)是不是到這里來了*/return transactionUtils.begin();}/*** 判斷是否加上注解了* 待會我會把整個(gè)代碼做個(gè)重構(gòu)* 重構(gòu)的話看起來就會舒服多了* 大家先忍耐一下* 做完了做重構(gòu)* 否則你們不知道重構(gòu)是怎么來的* 如果transactionStatus等于null說明了什么問題* 你們想一想* 我不需要給他開啟事務(wù)* 那我就不做任何操作* * * @param transactionStatus*/private void commit(TransactionStatus transactionStatus) {/*** 所以判斷不等于null的情況下* 走到這一步的話* 在方法上加上事務(wù)的注解了* 是不是這樣的* 這個(gè)時(shí)候我怎么辦* transactionUtils.commit* */if (transactionStatus != null) {/*** 5.如果存在注解,提交事務(wù)* 去提交這樣的一個(gè)事務(wù)*/transactionUtils.commit(transactionStatus);}}// 獲取方法上是否存在事務(wù)注解/*** 這段代碼直接copy過來* 我先給你們寫一下* 因?yàn)檫@段代碼比較長* 而且寫得話太浪費(fèi)時(shí)間了* 而且這段代碼也沒有什么意義* 這段代碼其實(shí)是怎么樣的一個(gè)目的* 給大家說一下* 你們猜也猜得到干嘛用的呢* 相當(dāng)于通過你的切入點(diǎn)* 獲取目標(biāo)代理對象方法* 是不是這樣的* 我在下去寫代碼的時(shí)候* 你知道我是怎么知道這API的嗎* 這也是你們要記住的思路* 沒有必要把任何代碼都記住* 什么意思呢* 這段代碼我開始也不知道通過這段代碼可以獲取代理對象的方法* 我怎么做呢* 先腦海中有這個(gè)思路* 然后我直接百度去找* AOP里面是怎么去獲取代理對象的方法* 就是這樣的* 明白這個(gè)意思沒有* 千萬別說我下去把API記住* 記一輩子沒用的* 我們寫是寫幾個(gè)步驟核心的* 這是我要給你們講的* 這理不理解* 沒必要記住* 我之前自己下去找這個(gè)方法的時(shí)候* 我會找很長時(shí)間的* 那這個(gè)方法看不看得懂什么意思* 獲取你代理對象的方法* 我把userServiceImpl的add給AOP進(jìn)行管理的情況下* 我們就可以去獲取這個(gè)方法* 這個(gè)都是能夠看得懂的* 如果這個(gè)看不懂那就說明有問題了* 獲取到之后* 然后怎么做呢* * * @param pjp* @return* @throws NoSuchMethodException* @throws SecurityException*/private ExtTransaction getMethodExtTransaction(ProceedingJoinPoint pjp)throws NoSuchMethodException, SecurityException {/*** 獲取目標(biāo)代理對象方法*/String methodName = pjp.getSignature().getName();/*** 獲取目標(biāo)代理對象*/Class<?> classTarget = pjp.getTarget().getClass();/*** 獲取目標(biāo)對象類型*/Class<?>[] par = ((MethodSignature) pjp.getSignature()).getParameterTypes();/*** 獲取目標(biāo)對象方法*/Method objMethod = classTarget.getMethod(methodName, par);/*** 就是獲取一下這個(gè)方法上有沒有加上@ExtTransaction注解* 是不是這樣的* 然后這個(gè)代碼寫完了之后呢* 然后ExtTransaction.class* 然后我們這邊拿到這個(gè)事務(wù)注解* */ExtTransaction extTransaction = objMethod.getDeclaredAnnotation(ExtTransaction.class);return extTransaction;}}
?
超強(qiáng)干貨來襲 云風(fēng)專訪:近40年碼齡,通宵達(dá)旦的技術(shù)人生總結(jié)
- 上一篇: 手写自定义注解实现思路
- 下一篇: springioc注解版运行效果演示