第2階段含數(shù)據(jù)庫(kù)開(kāi)發(fā)教程講義aop_第1頁(yè)
第2階段含數(shù)據(jù)庫(kù)開(kāi)發(fā)教程講義aop_第2頁(yè)
第2階段含數(shù)據(jù)庫(kù)開(kāi)發(fā)教程講義aop_第3頁(yè)
第2階段含數(shù)據(jù)庫(kù)開(kāi)發(fā)教程講義aop_第4頁(yè)
第2階段含數(shù)據(jù)庫(kù)開(kāi)發(fā)教程講義aop_第5頁(yè)
已閱讀5頁(yè),還剩54頁(yè)未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

事務(wù)是一組操作的集合,它是一個(gè)不可分割的工作單位。事務(wù)會(huì)把所有的操作作為一個(gè)整體,一起向數(shù)據(jù)庫(kù)提交或者是撤銷(xiāo)操作請(qǐng)求。所以這組操作要么同時(shí)成功,要么同時(shí)失敗。怎么樣來(lái)控制這組操作,讓這組操作同時(shí)成功或同時(shí)失敗呢?此時(shí)就要涉及到事務(wù)的具體操作了。事務(wù)的操作主要有三步:開(kāi)啟事務(wù)(一組操作開(kāi)始前,開(kāi)啟事務(wù)):starttransaction/begin提交事務(wù)(這組操作全部成功后,提交事務(wù)):commit;回滾事務(wù)(中間任何一個(gè)操作出現(xiàn)異常,回滾事務(wù)):rollback;簡(jiǎn)單的回顧了事務(wù)的概念以及事務(wù)的基本操作之后,接下來(lái)我們看一個(gè)事務(wù)管理案例:解散部門(mén)(解散需求:當(dāng)部門(mén)解散了不僅需要把部門(mén)信息刪除了,還需要把該部門(mén)下的員工數(shù)據(jù)也刪除了。步驟:33456789publicclassDeptServiceImplimplements{privateDeptMapperprivateEmpMapperpublicvoiddelete(Integer//根據(jù)部門(mén)id刪除部門(mén)信息}}1123456789publicinterfaceDeptMapper*根據(jù)id刪除部門(mén)信息*@param@Delete("deletefromdeptwhereid=#{id}")voiddeleteById(Integerid);部門(mén)}112345678publicinterfaceEmpMapper//根據(jù)部門(mén)id刪除部門(mén)下所有員工@Delete("deletefromempwherepublicintdeleteByDeptId(Integer}1123456789publicclassDeptServiceImplimplements{privateDeptMapperprivateEmpMapper//根據(jù)部門(mén)id,刪除部門(mén)信息及部門(mén)下的所有員工publicvoiddelete(Integer//根據(jù)部門(mén)id刪除部門(mén)信息inti=}}成了數(shù)據(jù)的不一致。先執(zhí)行根據(jù)id刪除部門(mén)的操作,這步執(zhí)行完畢,數(shù)據(jù)庫(kù)表dept中的數(shù)據(jù)就已經(jīng)刪除了。執(zhí)行1/0操作,拋出異常執(zhí)行。而要想保證操作前后,數(shù)據(jù)的一致性,就需要讓解散部門(mén)中涉及到的兩個(gè)業(yè)務(wù)操作,要么全部成功,要么全部失敗。那我們?nèi)绾?,讓這兩個(gè)操作要么全部成功,要么全部失敗呢?在方法運(yùn)行之前,開(kāi)啟事務(wù),如果方法成功執(zhí)行,就提交事務(wù),如果方法執(zhí)行的過(guò)程當(dāng)中出現(xiàn)異常了,就回滾事務(wù)。@Transactional@Transactional@Transactional類(lèi)接口下所有的實(shí)現(xiàn)類(lèi)當(dāng)中所有的方法都交給spring接下來(lái),我們就可以在業(yè)務(wù)方法delete上加上@Transactional來(lái)控制事務(wù)。1123456789publicclassDeptServiceImplimplements{privateDeptMapperprivateEmpMapper//publicvoiddelete(Integer//根據(jù)部門(mén)id刪除部門(mén)信息//inti=//刪除部門(mén)下的所有員工信息}}在業(yè)務(wù)功能上添加@Transactional注解進(jìn)行事務(wù)管理后,我們重啟SpingBoot服務(wù),使用n測(cè)試:說(shuō)明:可以在aplication.ml配置文件中開(kāi)啟事務(wù)管理日志,這樣就可以在控制看到和事務(wù)相關(guān)的日志信息了#spring#spring事務(wù)管理日志org.springframework.jdbc.support.JdbcTransactionManager:前面我們通過(guò)sping事務(wù)管理注解@Tranactional已經(jīng)控制了業(yè)務(wù)層方法的事務(wù)。接下來(lái)我們要來(lái)詳細(xì)的介紹一下@Tranactinal事務(wù)管理注解的使用細(xì)節(jié)。我們這里主要介紹@Tansactional注解當(dāng)中的兩個(gè)常見(jiàn)的屬性:1123456789publicvoiddelete(Integer//根據(jù)部門(mén)id刪除部門(mén)信息inti=}以上業(yè)務(wù)功能deete()方法在運(yùn)行時(shí),會(huì)除0的算數(shù)運(yùn)算異常(運(yùn)行時(shí)異常),出現(xiàn)異常之后,由于我們?cè)诜椒ㄉ霞恿薂Trnsactonal注解進(jìn)行事務(wù)管理,所以發(fā)生異常會(huì)執(zhí)行rollbck回滾操作,從而保證事務(wù)操作前后數(shù)據(jù)是一致的。下面我們?cè)谧鲆粋€(gè)測(cè)試,我們修改業(yè)務(wù)功能代碼,在模擬異常的位置上直接拋出Excetion異常(時(shí)異常)12123456789publicvoiddelete(Integerid)throwsException//根據(jù)部門(mén)id刪除部門(mén)信息//thrownewException("出現(xiàn)異常了}//刪除部門(mén)下的所有員工信息}說(shuō)明:在servie中向上拋出一個(gè)Excepion編譯時(shí)異常之后,由于是controller調(diào)用sevice,所以在controller中要有異常處理代碼,此時(shí)我們選擇在contrller常向上拋。3//4("根據(jù)id刪除部門(mén)5//調(diào)用service678return9}1212publicResultdelete(@PathVariableIntegerid)throwsException通過(guò)以上測(cè)試可以得出一個(gè)結(jié)論:默認(rèn)情況下,只有出現(xiàn)RuntieExcption(運(yùn)行時(shí)異常)事務(wù)。1123456789publicclassDeptServiceImplimplementsDeptService{privateDeptMapperprivateEmpMapperpublicvoiddelete(Integerid){//根據(jù)部門(mén)id刪除部門(mén)信息//intnum=//刪除部門(mén)下的所有員工信息} 在Spring的事務(wù)管理中,默認(rèn)只有運(yùn)行時(shí)異常RuntimeException才會(huì)回滾。我們接著繼續(xù)學(xué)習(xí)@Transactional注解當(dāng)中的第二個(gè)屬性propagation的行為的。例如:兩個(gè)事務(wù)方法,一個(gè)A方法,一個(gè)B方法。在這兩個(gè)方法上都添加了@Transactional表這兩個(gè)方法都具有事務(wù),而在A方法當(dāng)中又去調(diào)用了B方法。所謂事務(wù)的行為,指的就是在A方法運(yùn)行的時(shí)候,首先會(huì)開(kāi)啟一個(gè)事務(wù),在A方法當(dāng)中又調(diào)用了B方法,B方法自身也具有事務(wù),那么B方法在運(yùn)行的時(shí)候,到底是加入到A方法的事務(wù)當(dāng)中來(lái),還是B在運(yùn)行的時(shí)候新建一個(gè)事務(wù)?這個(gè)就涉及到了事務(wù)的行為。propagation屬性來(lái)指定行為。接下來(lái)我們就來(lái)介紹一下常見(jiàn)的事務(wù)行為… 由于解散部門(mén)是一個(gè)非常重要而且非常的操作,所以在業(yè)務(wù)當(dāng)中要求每一次執(zhí)行解散部門(mén)的操作都需要留下痕跡,就是要記錄操作日志。而且還要求無(wú)論是執(zhí)行成功了還是執(zhí)行失敗了,都需要留下痕跡。創(chuàng)建數(shù)據(jù)庫(kù)表dept_logcreatecreatetableidintauto_incrementcomment'主鍵ID'primarycreate_timedatetimenullcomment'操作時(shí)間descriptionvarchar(300)nullcomment'操作描述)comment'部門(mén)操作日志表publicclassDeptLogprivateIntegerprivateLocalDateTimeprivateString publicinterface{4567@Insert("insertintodept_log(create_time,description)voidinsert(DeptLog}publicpublicinterfaceDeptLogServicevoidinsert(DeptLog 1123456789publicclassDeptLogServiceImplimplementsDeptLogServiceprivateDeptLogMapper@Transactional//事務(wù)行為:有事務(wù)就加入、沒(méi)有事務(wù)就新建事務(wù)publicvoidinsert(DeptLog{}}45645678publicclassDeptServiceImplimplements{privateDeptMapper123制//當(dāng)前業(yè)務(wù)實(shí)現(xiàn)類(lèi)中的所有的方法,都添加了spring事務(wù)管理機(jī) privateEmpMapperempMapper;privateDeptLogServicedeptLogService;//根據(jù)部門(mén)id@Transactional(rollbackFor=publicvoiddelete(Integerid)throwsExceptiontry//根據(jù)部門(mén)id刪除部門(mén)信息//模擬:異常thrownewException("出現(xiàn)異常了 //}finally//不論是否有異常,最終都要執(zhí)行的代碼:記錄日志DeptLogdeptLog=new deptLog.setDescription("執(zhí)行了解散部門(mén)的操作,此時(shí)解散的是"+id+"號(hào)部門(mén)");// //省略其他代碼 執(zhí)行了刪除3號(hào)部門(mén)操作執(zhí)行了插入部門(mén)日志操作當(dāng)執(zhí)行insert操作時(shí),inset設(shè)置的事務(wù)行是默認(rèn)值REQUIRED表有務(wù)就入,有則新建事務(wù)此時(shí):delete和inset操作使用了同一個(gè)事務(wù),同一個(gè)事務(wù)中的多個(gè)操作,要么同時(shí)成功,要么同時(shí)失敗,所以當(dāng)異常發(fā)生時(shí)進(jìn)行事務(wù)回滾,就會(huì)回滾deete和inset操作在DeptLogServiceImpl類(lèi)中insert方法上,添加@Transactional(propagationPropagation.REQUIRES_NEWPropagation.REQUIRES_NEW1234567publicclassDeptLogServiceImplimplementsDeptLogServiceprivateDeptLogMapper@Transactional(propagation=Propagation.REQUIRES_NEW)//事務(wù)行為:不論是否有事務(wù),都新建事務(wù)89publicvoidinsert(DeptLog{}}那此時(shí),DeptServiceImpl中的delete方法運(yùn)行時(shí),會(huì)開(kāi)啟一個(gè)事務(wù)。當(dāng)調(diào)用deptLogService.insert(deptLog)時(shí),也會(huì)創(chuàng)建一個(gè)新的事務(wù),那此時(shí),當(dāng)insert方法運(yùn)行完畢之后,事務(wù)就已經(jīng)提交了。即使外部的事務(wù)出現(xiàn)異常,內(nèi)部已經(jīng)提交的事務(wù),也不會(huì)回滾了,因REQUIREDREQUIRED:大部分情況下都是用 REQUIRES_NEWREQUIRES_NEW:當(dāng)我們不希望事務(wù)之間相互影響時(shí),可以使用該 學(xué)習(xí)完spring的事務(wù)管理之后,接下來(lái)我們進(jìn)入到AOP的學(xué)習(xí)。AOP也是spring框架的第二大,在AOP基礎(chǔ)這個(gè)階段,我們首先介紹一下什么是AOP,再通過(guò)一個(gè)快速程序,讓大家快速體驗(yàn)AOP程序的開(kāi)發(fā)。最后再介紹AOP當(dāng)中所涉及到的一些的概念。AOP英文全稱(chēng):AspectOrientedProgramming(面向切面編程、面向方面編程),其實(shí)說(shuō)白那什么又是面向方法編程呢,為什么又需要面向方法編程呢?來(lái)我們舉個(gè)例子做一個(gè)說(shuō)明:比如,我們這里有一個(gè)項(xiàng)目,項(xiàng)目中開(kāi)發(fā)了很多的業(yè)務(wù)功能。然而有一些業(yè)務(wù)功能執(zhí)行效率比較低,執(zhí)行耗時(shí)較長(zhǎng),我們需要針對(duì)于這些業(yè)務(wù)方法進(jìn)行優(yōu)化。那首先可能多數(shù)人首先想到的就是在每一個(gè)業(yè)務(wù)方法運(yùn)行之前,記錄這個(gè)方法運(yùn)行的開(kāi)始時(shí)間。在這個(gè)方法運(yùn)行完畢之后,再來(lái)記錄這個(gè)方法運(yùn)行的結(jié)束時(shí)間。拿結(jié)束時(shí)間減去開(kāi)始時(shí)間,不就是這個(gè)方法的執(zhí)行耗時(shí)嗎?個(gè)業(yè)務(wù)模塊又包含很多增刪改查的方法,如果我們要在每一個(gè)模塊下的業(yè)務(wù)方法中,添加記錄開(kāi)始時(shí)間、AOPAOP的作用:在程序運(yùn)行期間在不修改源代碼的基礎(chǔ)上對(duì)已有方法進(jìn)行增強(qiáng)(無(wú)侵入性:解耦我們要想完成統(tǒng)計(jì)各個(gè)業(yè)務(wù)方法執(zhí)行耗時(shí)的需求,我們只需要定義一個(gè)模板方法,將記錄方法執(zhí)行耗時(shí)這一部分公共的邏輯代碼,定義在模板方法當(dāng)中,在這個(gè)方法開(kāi)始運(yùn)行之前,來(lái)記錄這個(gè)方法運(yùn)行的開(kāi)始時(shí)間,在方法結(jié)束運(yùn)行的時(shí)候,再來(lái)記錄方法運(yùn)行的結(jié)束時(shí)間,中間就來(lái)運(yùn)行原始的業(yè)務(wù)方法。而中間運(yùn)行的原始業(yè)務(wù)方法,可能是其中的一個(gè)業(yè)務(wù)方法,比如:我們只想通過(guò)部門(mén)管理的list方法的執(zhí)行耗時(shí),那就只有這一個(gè)方法是原始業(yè)務(wù)方法。而如果,我們是先想統(tǒng)計(jì)所有部門(mén)管理的業(yè)務(wù)方法執(zhí)行耗時(shí),那此時(shí),所有的部門(mén)管理的業(yè)務(wù)方法都是原始業(yè)務(wù)方法。那面向這樣的指定的一個(gè)或多個(gè)方法進(jìn)行編程,我們就稱(chēng)之為面向切面編程。那此時(shí),當(dāng)我們?cè)僬{(diào)用部門(mén)管理的list業(yè)務(wù)方法時(shí)啊,并不會(huì)直接執(zhí)行l(wèi)ist方法的邏輯,而是會(huì)執(zhí)行我們所定義的模板方法,然后再模板方法中:運(yùn)行原始的業(yè)務(wù)方法(那此時(shí)原始的業(yè)務(wù)方法,就是list方法)不論,我們運(yùn)行的是那個(gè)業(yè)務(wù)方法,最后其實(shí)運(yùn)行的就是我們定義的模板方法,而在模板方法中,就完成了原始方法執(zhí)行耗時(shí)的統(tǒng)計(jì)操作。(那這樣呢,我們就通過(guò)一個(gè)模板方法就完成了指定的一個(gè)或多個(gè)業(yè)務(wù)方法執(zhí)行耗時(shí)的統(tǒng)計(jì))對(duì)了,就是和我們之前所學(xué)習(xí)的動(dòng)態(tài)技術(shù)是非常類(lèi)似的。我們所說(shuō)的模板方法,其實(shí)就是對(duì)象中所定義的方法,那對(duì)象中的方法以及根據(jù)對(duì)應(yīng)的業(yè)務(wù)需要,完成了對(duì)應(yīng)的業(yè)務(wù)功能,當(dāng)運(yùn)行原其實(shí),AOP面向切面編程和OOP面向?qū)ο缶幊桃粯樱鼈兌純H僅是一種編程思想,而動(dòng)態(tài)技術(shù)是這種思想最主流的實(shí)現(xiàn)方式。而Sping的AOP是Spring框架的高級(jí)技術(shù),旨在管理bean對(duì)象的過(guò)程中底層使用動(dòng)態(tài)機(jī)制,對(duì)特定的方法進(jìn)行編程(功能增強(qiáng))。在了解了什么是AOP后,我們下面通過(guò)一個(gè)快速程序,體驗(yàn)下AOP的開(kāi)發(fā),并掌握Spring中AOP的開(kāi)發(fā)步驟。@Aspect//當(dāng)前類(lèi)為切面類(lèi)publicclass{6789@Around("execution(*com.itheima.service.*.*(..))")publicObjectrecordTime(ProceedingJoinPointpjp)throwsThrowable//longbegin=//執(zhí)行原始方法Objectresult=//longend=(pjp.getSignature()+"執(zhí)行耗時(shí):{}毫秒",end-return}}我們通過(guò)AOP程序完成了業(yè)務(wù)方法執(zhí)行耗時(shí)的統(tǒng)計(jì),那其實(shí)AOP功能不止此,見(jiàn)的用場(chǎng)景如下:事務(wù)管理:我們前面所講解的Spring事務(wù)管理,底層其實(shí)也是通過(guò)AOP來(lái)實(shí)現(xiàn)的,只要添加@Tansactionl注解之后,AOP程序自動(dòng)會(huì)在原始方法運(yùn)行前先來(lái)開(kāi)啟事務(wù),在原始方法運(yùn)行完畢之后提交或回滾事務(wù)代碼無(wú)侵入:沒(méi)有修改原始的業(yè)務(wù)方法,就已經(jīng)對(duì)原始的業(yè)務(wù)方法進(jìn)行了功能的增強(qiáng)或者是功能的改變通過(guò)SpringAOP的快速,感受了一下AOP面向切面編程的開(kāi)發(fā)方式。下面我們?cè)賮?lái)學(xué)習(xí)AOP及到的一些概念。連接點(diǎn)指的是可以被aop控制的方法。例如:程序當(dāng)中所有的業(yè)務(wù)方法都是可以被aop的方法。在SprinAOP提供的JoinPont當(dāng)中,封裝了連接點(diǎn)方法在執(zhí)行時(shí)的相關(guān)信息。(的講解)在程序中是需要統(tǒng)計(jì)各個(gè)業(yè)務(wù)方法的執(zhí)行耗時(shí)的,此時(shí)我們就需要在這些業(yè)務(wù)方法運(yùn)行開(kāi)始之前,先記錄這個(gè)方法運(yùn)行的開(kāi)始時(shí)間,在每一個(gè)業(yè)務(wù)方法運(yùn)行結(jié)束的時(shí)候,再來(lái)記錄這個(gè)方法運(yùn)行的結(jié)束時(shí)間。但是在AOP面向切面編程當(dāng)中,我們只需要將這部分重復(fù)的代碼邏輯抽取出來(lái)單獨(dú)定義。抽取出來(lái)的這一部分重復(fù)的邏輯,也就是共性的功能。在通知當(dāng)中,我們所定義的共性功能到底要應(yīng)用在哪些方法上?此時(shí)就涉及到了切入點(diǎn)t概念。切入點(diǎn)指的是匹配連接點(diǎn)的條件。通知僅會(huì)在切入點(diǎn)方法運(yùn)行時(shí)才會(huì)被應(yīng)用。假如:切入點(diǎn)表達(dá)式改為DepterviceImp.list(),此時(shí)就代表僅僅只有l(wèi)istlit()方法在運(yùn)行的時(shí)候才會(huì)應(yīng)用通知。當(dāng)通知和切入點(diǎn)結(jié)合在一起,就形成了一個(gè)切面。通過(guò)切面就能夠描述當(dāng)前aopAOP的概念我們介紹完畢之后,接下來(lái)我們?cè)賮?lái)分析一下我們所定義是如何與目標(biāo)對(duì)象結(jié)合Sping的AOP底層是基于動(dòng)態(tài)技術(shù)來(lái)實(shí)現(xiàn)的,也就是說(shuō)在程序運(yùn)行的時(shí)候,會(huì)自動(dòng)的基于動(dòng)態(tài)技術(shù)為目標(biāo)對(duì)象生成一個(gè)對(duì)應(yīng)的對(duì)象。在對(duì)象當(dāng)中就會(huì)對(duì)目標(biāo)對(duì)象當(dāng)中的原始方法進(jìn)行功能的增強(qiáng)。@Around(@Around("execution(*publicObjectrecordTime(ProceedingJoinPointpjp)throwsThrowable//longbegin=//執(zhí)行原始方法Objectresult=//longend=//(pjp.getSignature()+"執(zhí)行耗時(shí):{}毫秒",end-return @After:后置通知,此注解標(biāo)注方法在目標(biāo)方法后被執(zhí)行,無(wú)論是否有異常都會(huì)執(zhí)行@AfterReturning:返回后通知,此注解標(biāo)注方法在目標(biāo)方法后被執(zhí)行,有異常不會(huì)執(zhí)行@AfterThrowing:異常后通知,此注解標(biāo)注方法發(fā)生異常后執(zhí)行1123456789publicclassMyAspect1//@Before("execution(*com.itheima.service.*.*(..))")publicvoidbefore(JoinPointjoinPoint){("before}//@Around("execution(*publicObjectaround(ProceedingJoinPointproceedingJoinPoint)throwsThrowable{("aroundbefore//調(diào)用目標(biāo)對(duì)象的原始方法執(zhí)行Objectresult=//原始方法如果執(zhí)行時(shí)有異常,環(huán)繞通知中的后置代碼不會(huì)在執(zhí)行了("aroundafter...");return}//@After("execution(*com.itheima.service.*.*(..))")publicvoidafter(JoinPointjoinPoint){("after}//返回后通知(程序在正常執(zhí)行的情況下,會(huì)執(zhí)行的后置通知}}@AfterReturning("execution(*com.itheima.service.*.*(..))")publicvoidafterReturning(JoinPointjoinPoint){("afterReturning}//異常通知(程序在出現(xiàn)異常的情況下,執(zhí)行的后置通知publicvoidafterThrowing(JoinPoint 修改DeptServiceImpl業(yè)務(wù)實(shí)現(xiàn)類(lèi)中的代碼:添加異常 223456789publicclassDeptServiceImplimplements{privateDeptMapperpublicList<Dept>list()List<Dept>deptList=intnum=return}//省略其他代碼}@Around環(huán)繞通知需要自己調(diào)用ProceedingJoinPceed()來(lái)讓原始方法執(zhí)行,其1123456789//@Before("execution(*//@Around("execution(*//@After("execution(*//返回后通知(程序在正常執(zhí)行的情況下,會(huì)執(zhí)行的后置通知)//異常通知(程序在出現(xiàn)異常的情況下,執(zhí)行的后置通知)我們發(fā)現(xiàn)啊,每一個(gè)注解里面都指定了切入點(diǎn)表達(dá)式,而且這些切入點(diǎn)表達(dá)式都一模一樣。此時(shí)我們的代碼當(dāng)中就存在了大量的重復(fù)性的切入點(diǎn)表達(dá)式,假如此時(shí)切入點(diǎn)表達(dá)式需要變動(dòng),就需要將所有的切入點(diǎn)表達(dá)式一個(gè)一個(gè)的來(lái)改動(dòng),就變得非常繁瑣了。怎么來(lái)解決這個(gè)切入點(diǎn)表達(dá)式重復(fù)的問(wèn)題?答案就是:Spring提供了@PointCut注解,該注解的作用是將公共的切入點(diǎn)表達(dá)式抽取出來(lái),需要用到時(shí)該1123456789publicclassMyAspect1//切入點(diǎn)方法(公共的切入點(diǎn)表達(dá)式@Pointcut("execution(*privatevoid}//前置通知切入點(diǎn)publicvoidbefore(JoinPointjoinPoint){("before...");}publicObjectaround(ProceedingJoinPointproceedingJoinPoint)throwsThrowable{("aroundbeforeObjectresult=("aroundafter...");returnresult;}publicvoidafter(JoinPointjoinPoint){("after...");}//返回后通知(程序在正常執(zhí)行的情況下,會(huì)執(zhí)行的后置通知)publicvoidafterReturning(JoinPointjoinPoint){("afterReturning}//異常通知(程序在出現(xiàn)異常的情況下,執(zhí)行的后置通知)publicvoidafterThrowing(JoinPointjoinPoint){("afterThrowing...");}}需要注意的是:當(dāng)切入點(diǎn)方法使用private修飾時(shí),僅能在當(dāng)前切面類(lèi)中該表達(dá)式,他切面類(lèi)中也要當(dāng)前類(lèi)中的切入點(diǎn)表達(dá)式,就需要把prvate改為pulic,而在的時(shí)候,具體的語(yǔ)法為:1123456789publicclassMyAspect2publicvoidbefore(){("MyAspect2->before}}當(dāng)在項(xiàng)目開(kāi)發(fā)當(dāng)中,我們定義了多個(gè)切面類(lèi),而多個(gè)切面類(lèi)中多個(gè)切入點(diǎn)都匹配到了同一個(gè)目標(biāo)方法。此時(shí)當(dāng)目標(biāo)方法在運(yùn)行的時(shí)候,這多個(gè)切面類(lèi)當(dāng)中的這些通知方法都會(huì)運(yùn)行。 1123456789publicclassMyAspect2//@Before("execution(*com.itheima.service.*.*(..))")publicvoidbefore(){("MyAspect2->before}//@After("execution(*com.itheima.service.*.*(..))")publicvoidafter(){("MyAspect2->after}}12123456789publicclassMyAspect3//@Before("execution(*com.itheima.service.*.*(..))")publicvoidbefore(){("MyAspect3->before}//@After("execution(*com.itheima.service.*.*(..))")publicvoidafter(){("MyAspect3-after}}123456789publicclassMyAspect4//@Before("execution(*com.itheima.service.*.*(..))")publicvoidbefore(){("MyAspect4->before}//@After("execution(*com.itheima.service.*.*(..))")publicvoidafter(){("MyAspect4->after}} 目標(biāo)方法前方法:字母靠前的先執(zhí)行1234越后執(zhí)行//切面類(lèi)的執(zhí)行順序(前置通知:數(shù)字越小先執(zhí)行;后置通知:數(shù)字越小5publicclassMyAspect267@Before("execution(*8("MyAspect2->before}@After("execution(*("MyAspect2->after}}1231234越后執(zhí)行//切面類(lèi)的執(zhí)行順序(前置通知:數(shù)字越小先執(zhí)行后置通知:數(shù)字越小56789publicclassMyAspect3//@Before("execution(*com.itheima.service.*.*(..))")publicvoidbefore(){("MyAspect3->before}//@After("execution(*("MyAspect3-after}}@Order(1//切面類(lèi)的執(zhí)行順序(前置通知:數(shù)字越小先執(zhí)行后置通知:數(shù)字越小越后執(zhí)行)publicclassMyAspect467@Before("execution(*8("MyAspect4->before}@After("execution(*("MyAspect4->after}}從AOP的程序到現(xiàn)在,都在使用切入點(diǎn)表達(dá)式來(lái)描述切入點(diǎn)。下面我們就來(lái)詳細(xì)的介紹一下切入點(diǎn)表達(dá)式的具體寫(xiě)法。@annotation(……) 修飾符?返回 包名.類(lèi)名.?方法名(方法參數(shù))throws異常修飾符:可省略(比如public、protected)包名.類(lèi)名:可省略throws異常:可省略(注意是方法上拋出的異常,不是實(shí)際拋出的異常) *:?jiǎn)蝹€(gè)獨(dú)立的任意符號(hào),可以通配任意返回值、包名、類(lèi)名、方法名、任意類(lèi)型的一個(gè)參數(shù),也可以通配包、類(lèi)、方法名的一部分*返回值可以使用*號(hào)代替(任意返回值類(lèi)型*號(hào)代替,代表任意包(一層包使用一個(gè)*使用***

) )使用*代替包名(一層包使用一個(gè)* execution(** execution(** execution(* execution(* execution(*根據(jù)業(yè)務(wù)需要,可以使用且(&&)、或(||)、非(!) execution(*com.itheima.service.DeptService.list(..))||execution(*com.itheima.service.DeptService.delete(..))所有業(yè)務(wù)方法名在命名時(shí)盡量規(guī)范,方便切入點(diǎn)表達(dá)式快速匹配。如:查詢(xún)類(lèi)方法都是find開(kāi)12123456789//publicclassDeptServiceImplimplementsDeptServicepublicList<Dept>findAllDept()//省略代碼}publicDeptfindDeptById(Integerid)//省略代碼}publicvoidupdateDeptById(Integerid)//省略代碼}publicvoid//省略代碼}//其他代碼dept)}//匹配DeptServiceImpl類(lèi)中以findexecution(* execution(*在滿(mǎn)足業(yè)務(wù)需要的前提下,盡量縮小切入點(diǎn)的匹配范圍。如:包名匹配盡量不使用..,使用 execution(*已經(jīng)學(xué)習(xí)了exection切入點(diǎn)表達(dá)式的語(yǔ)法。那么如果我們要匹配多個(gè)無(wú)規(guī)則的方法,比如:)和delet()這兩個(gè)方法。這個(gè)時(shí)候我們基于excutin這種切入點(diǎn)表達(dá)式來(lái)描述就不是很方便了。而在之前我們是將兩個(gè)切入點(diǎn)表達(dá)式組合在了一起完成的需求,這個(gè)是比較繁瑣的。我們可以借助于另一種切入點(diǎn)表達(dá)式annottion來(lái)描述這一類(lèi)的切入點(diǎn),從而來(lái)簡(jiǎn)化切入點(diǎn)表達(dá)式的書(shū)寫(xiě)。自定義注解11234public@interfaceMyLog{}業(yè)務(wù)類(lèi)1123456789publicclassDeptServiceImplimplements{privateDeptMapper@MyLog//自定義注解(表示:當(dāng)前方法屬于目標(biāo)方法)publicList<Dept>list(){List<Dept>deptList=////intnum=return} //自定義注解(表示:當(dāng)前方法屬于目標(biāo)方法publicvoiddelete(Integerid)//1.}publicvoidsave(Dept{}publicDeptgetById(Integer{return}publicvoidupdate(Dept{}}1123456789publicclassMyAspect6//針對(duì)list方法、delete//publicvoidbefore(){("MyAspect6->before}("MyAspect6->after}}annotation基于注解的方式來(lái)匹配切入點(diǎn)方法。這種方式雖然多一步操作,我們需要自定義一個(gè)注解,但是相對(duì)來(lái)比較靈活。我們需要匹配哪個(gè)方法,就在方法上加上對(duì)應(yīng)的注解就可以了講解完了切入點(diǎn)表達(dá)式之后,接下來(lái)我們?cè)賮?lái)講解最后一個(gè)部分連接點(diǎn)。我們前面在講解AOP念的時(shí)候,我們提到過(guò)什么是連接點(diǎn),連接點(diǎn)可以簡(jiǎn)單理解為可以被AOP控制的方法。我們目標(biāo)對(duì)象當(dāng)中所有的方法是不是都是可以被AOP控制的方法。而在SprinAOP在Spring中用JoinPint抽象了連接點(diǎn),用它可以獲得方法執(zhí)行時(shí)的相關(guān)信息,如目標(biāo)類(lèi)名、方法名、方法參數(shù)等。對(duì)于其他四種通知,獲取連接點(diǎn)信息只能使用JoinPoint,它是ProcedingJoinPint1123456789publicclassMyAspect7privatevoid//publicvoidjoinPoint){(joinPoint.getSignature().getName()+"MyAspect7->before//publicvoidjoinPoint){(joinPoint.getSignature().getName()+"MyAspect7->after//publicObjectaround(ProceedingJoinPointpjp)throwsThrowable//獲取目標(biāo)類(lèi)名Stringnamepjp.getTarget().getClass().getName();//目標(biāo)方法名StringmethodNamepjp.getSignature().getName();//Object[]args=("目標(biāo)方法參數(shù):{}",//ObjectreturnValue=return}}SpingAOP的相關(guān)知識(shí)我們就已經(jīng)全部學(xué)習(xí)完畢了。最后我們要通過(guò)一個(gè)案例來(lái)對(duì)AOP應(yīng)用。就是當(dāng)部門(mén)管理和員工管理當(dāng)中的增、刪、改相關(guān)功能接口時(shí),需要詳細(xì)的操作日志,并保存所記錄的日志信息包括當(dāng)前接口的操作人是誰(shuí)操作的,什么時(shí)間點(diǎn)操作的,以及的是哪個(gè)類(lèi)當(dāng)中的哪個(gè)方法,在這個(gè)方法的時(shí)候傳入進(jìn)來(lái)的參數(shù)是什么,這個(gè)方法最終拿到的返回值是以上兩個(gè)問(wèn)題的解決方案:可以使用AOP解決(每一個(gè)增刪改功能接口中要實(shí)現(xiàn)的記錄操作日志的邏輯代碼是相同)??梢园堰@部分記錄操作日志的通用的、重復(fù)性的邏輯代碼抽取出來(lái)定義在一個(gè)通知方法當(dāng)中,我們可以把這部分記錄操作日志的通用的、重復(fù)性的邏輯代碼抽取出來(lái)定義在一個(gè)通知方法當(dāng)中,我們通過(guò)AOP面向切面編程的方式,在不改動(dòng)原始功能的基礎(chǔ)上來(lái)對(duì)原始的功能進(jìn)行增強(qiáng)。目前我們所增強(qiáng)的功能就是來(lái)記錄操作日志,所以也可以使用AOP的技術(shù)來(lái)實(shí)現(xiàn)。使用AOP的技術(shù)來(lái)實(shí)現(xiàn)也是最為簡(jiǎn)單,最為方便的。問(wèn)題3:既然要基于AOP面向切面編程的方式來(lái)完成的功能,那么我們要使用AOP五種通知類(lèi)型當(dāng)中的 方法的運(yùn)行時(shí)長(zhǎng),需要原始方法運(yùn)行之前記錄開(kāi)始時(shí)間,原始方法運(yùn)行之后記錄結(jié)束時(shí)間。通過(guò)計(jì)算獲得方法的執(zhí)行耗時(shí)。要匹配業(yè)務(wù)接口當(dāng)中所有的增刪改的方法,而增刪改方法在命名上沒(méi)有共同的前綴或后綴。此時(shí)如果使用execution切入點(diǎn)表達(dá)式也可以,但是會(huì)比較繁瑣。當(dāng)遇到增刪改的方法名沒(méi)有規(guī)律時(shí),就可以使用annotation<!--AOP<!--AOP起步依賴(lài)----createtableidintunsignedprimarykeyauto_incrementcommentoperate_userintunsignedcomment'操作人operate_timedatetimecomment'操作時(shí)間class_namevarchar(100)comment'操作的類(lèi)名method_namevarchar(100)comme

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論