日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > java >内容正文

java

Java程序员从笨鸟到菜鸟之(七十四)细谈Spring(六)spring之AOP基本概念和配置详解

發(fā)布時(shí)間:2025/3/21 java 16 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java程序员从笨鸟到菜鸟之(七十四)细谈Spring(六)spring之AOP基本概念和配置详解 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

首先我們來(lái)看一下官方文檔所給我們的關(guān)于AOP的一些概念性詞語(yǔ)的解釋:

切面(Aspect):一個(gè)關(guān)注點(diǎn)的模塊化,這個(gè)關(guān)注點(diǎn)可能會(huì)橫切多個(gè)對(duì)象。事務(wù)管理是J2EE應(yīng)用中一個(gè)關(guān)于橫切關(guān)注點(diǎn)的很好的例子。在spring?AOP中,切面可以使用基于模式)或者基于Aspect注解方式來(lái)實(shí)現(xiàn)。通俗點(diǎn)說(shuō)就是我們加入的切面類(比如log類),可以這么理解。

連接點(diǎn)(Joinpoint:在程序執(zhí)行過(guò)程中某個(gè)特定的點(diǎn),比如某方法調(diào)用的時(shí)候或者處理異常的時(shí)候。在Spring?AOP中,一個(gè)連接點(diǎn)總是表示一個(gè)方法的執(zhí)行。通俗的說(shuō)就是加入切點(diǎn)的那個(gè)點(diǎn)

通知(Advice:在切面的某個(gè)特定的連接點(diǎn)上執(zhí)行的動(dòng)作。其中包括了“around”“before”“after”等不同類型的通知(通知的類型將在后面部分進(jìn)行討論)。許多AOP框架(包括Spring)都是以攔截器做通知模型,并維護(hù)一個(gè)以連接點(diǎn)為中心的攔截器鏈。

切入點(diǎn)(Pointcut:匹配連接點(diǎn)的斷言。通知和一個(gè)切入點(diǎn)表達(dá)式關(guān)聯(lián),并在滿足這個(gè)切入點(diǎn)的連接點(diǎn)上運(yùn)行(例如,當(dāng)執(zhí)行某個(gè)特定名稱的方法時(shí))。切入點(diǎn)表達(dá)式如何和連接點(diǎn)匹配是AOP的核心:Spring缺省使用AspectJ切入點(diǎn)語(yǔ)法。

引入(Introduction:用來(lái)給一個(gè)類型聲明額外的方法或?qū)傩?#xff08;也被稱為連接類型聲明(inter-type?declaration))。Spring允許引入新的接口(以及一個(gè)對(duì)應(yīng)的實(shí)現(xiàn))到任何被代理的對(duì)象。例如,你可以使用引入來(lái)使一個(gè)bean實(shí)現(xiàn)IsModified接口,以便簡(jiǎn)化緩存機(jī)制。

目標(biāo)對(duì)象(Target?Object:?被一個(gè)或者多個(gè)切面所通知的對(duì)象。也被稱做被通知(advised)對(duì)象。?既然Spring?AOP是通過(guò)運(yùn)行時(shí)代理實(shí)現(xiàn)的,這個(gè)對(duì)象永遠(yuǎn)是一個(gè)被代理(proxied)對(duì)象。

AOP代理(AOP?ProxyAOP框架創(chuàng)建的對(duì)象,用來(lái)實(shí)現(xiàn)切面契約(例如通知方法執(zhí)行等等)。在Spring中,AOP代理可以是JDK動(dòng)態(tài)代理或者CGLIB代理。

織入(Weaving:把切面連接到其它的應(yīng)用程序類型或者對(duì)象上,并創(chuàng)建一個(gè)被通知的對(duì)象。這些可以在編譯時(shí)(例如使用AspectJ編譯器),類加載時(shí)和運(yùn)行時(shí)完成。Spring和其他純Java?AOP框架一樣,在運(yùn)行時(shí)完成織入。



通知類型:

前置通知(Before?advice:在某連接點(diǎn)之前執(zhí)行的通知,但這個(gè)通知不能阻止連接點(diǎn)之前的執(zhí)行流程(除非它拋出一個(gè)異常)。

后置通知(After?returning?advice:在某連接點(diǎn)正常完成后執(zhí)行的通知:例如,一個(gè)方法沒(méi)有拋出任何異常,正常返回。

異常通知(After?throwing?advice:在方法拋出異常退出時(shí)執(zhí)行的通知。

最終通知(After?(finally)?advice:當(dāng)某連接點(diǎn)退出的時(shí)候執(zhí)行的通知(不論是正常返回還是異常退出)。

環(huán)繞通知(Around?Advice):包圍一個(gè)連接點(diǎn)的通知,如方法調(diào)用。這是最強(qiáng)大的一種通知類型。環(huán)繞通知可以在方法調(diào)用前后完成自定義的行為。它也會(huì)選擇是否繼續(xù)執(zhí)行連接點(diǎn)或直接返回它自己的返回值或拋出異常來(lái)結(jié)束執(zhí)行。

環(huán)繞通知是最常用的通知類型。和AspectJ一樣,Spring提供所有類型的通知,我們推薦你使用盡可能簡(jiǎn)單的通知類型來(lái)實(shí)現(xiàn)需要的功能。例如,如果你只是需要一個(gè)方法的返回值來(lái)更新緩存,最好使用后置通知而不是環(huán)繞通知,盡管環(huán)繞通知也能完成同樣的事情。用最合適的通知類型可以使得編程模型變得簡(jiǎn)單,并且能夠避免很多潛在的錯(cuò)誤。比如,你不需要在JoinPoint上調(diào)用用于環(huán)繞通知的proceed()方法,就不會(huì)有調(diào)用的問(wèn)題。



spring?AOP的實(shí)現(xiàn)

??????在spring2.5中,常用的AOP實(shí)現(xiàn)方式有兩種。第一種是基于xml配置文件方式的實(shí)現(xiàn),第二種是基于注解方式的實(shí)現(xiàn)。接下來(lái),以具體的示例來(lái)講解這兩種方式的使用。下面我們要用到的實(shí)例是一個(gè)注冊(cè),就有用戶名和密碼,我們利用AOP來(lái)實(shí)現(xiàn)在用戶注冊(cè)的時(shí)候?qū)崿F(xiàn)在保存數(shù)據(jù)之前和之后或者是拋出異常時(shí),在這些情況下都給他加上日志。在這里我們只講解AOP,所以我只把關(guān)鍵代碼貼出來(lái),不相干的就不貼了。

首先我們來(lái)看一下業(yè)務(wù)邏輯service層:

[java]?view plaincopy print?
  • /**?
  • ?*?RegisterService的實(shí)現(xiàn)類?
  • ?*?@author?曹勝歡?*/??
  • public?class?RegisterServiceImpl?implements?RegisterService?{??
  • ????private??RegisterDao?registerDao;??
  • ????public?RegisterServiceImpl()?{}??
  • ????/**?帶參數(shù)的構(gòu)造方法?*/??
  • ????public?RegisterServiceImpl(RegisterDao??registerDao){??
  • ????????this.registerDao?=registerDao;??
  • ????}??
  • ????public?void?save(String?loginname,?String?password)?{??
  • ????????registerDao.save(loginname,?password);??
  • ????????throw?new?RuntimeException("故意拋出一個(gè)異常。。。。");??
  • ????}??
  • ??????/**?set方法?*/??
  • ????public?void?setRegisterDao(RegisterDao?registerDao)?{??
  • ????????this.registerDao?=?registerDao;??
  • }}??


  • 對(duì)于業(yè)務(wù)系統(tǒng)來(lái)說(shuō),RegisterServiceImpl類就是目標(biāo)實(shí)現(xiàn)類,它的業(yè)務(wù)方法,如save()方法的前后或代碼會(huì)出現(xiàn)異常的地方都是AOP的連接點(diǎn)。

    ?

    下面是日志服務(wù)類的代碼:


    [java]?view plaincopy print?
  • /**?
  • ?*?日志切面類?
  • ?*?@author?曹勝歡?
  • ?*/??
  • public?class?LogAspect?{??
  • ????//任何通知方法都可以將第一個(gè)參數(shù)定義為?org.aspectj.lang.JoinPoint類型???
  • ????public?void?before(JoinPoint?call)?{??
  • ????????//獲取目標(biāo)對(duì)象對(duì)應(yīng)的類名??
  • ????????String?className?=?call.getTarget().getClass().getName();??
  • ????????//獲取目標(biāo)對(duì)象上正在執(zhí)行的方法名??
  • ????????String?methodName?=?call.getSignature().getName();??
  • ????????System.out.println("前置通知:"?+?className?+?"類的"?+?methodName?+?"方法開始了");??
  • ????}??
  • ????public?void?afterReturn()?{??
  • ????????System.out.println("后置通知:方法正常結(jié)束了");??
  • ????}??
  • ????public?void?after(){??
  • ????????System.out.println("最終通知:不管方法有沒(méi)有正常執(zhí)行完成,一定會(huì)返回的");??
  • ????}??
  • ????public?void?afterThrowing()?{??
  • ????????System.out.println("異常拋出后通知:方法執(zhí)行時(shí)出異常了");??
  • ????}??
  • ????//用來(lái)做環(huán)繞通知的方法可以第一個(gè)參數(shù)定義為org.aspectj.lang.ProceedingJoinPoint類型??
  • ????public?Object?doAround(ProceedingJoinPoint?call)?throws?Throwable?{??
  • ????????Object?result?=?null;??
  • ????????this.before(call);//相當(dāng)于前置通知??
  • ????????try?{??
  • ????????????result?=?call.proceed();??
  • ????????????this.afterReturn();?//相當(dāng)于后置通知??
  • ????????}?catch?(Throwable?e)?{??
  • ????????????this.afterThrowing();??//相當(dāng)于異常拋出后通知??
  • ????????????throw?e;??
  • ????????}finally{??
  • ????????????this.after();??//相當(dāng)于最終通知??
  • ????????}??
  • ????????return?result;??
  • ????}??
  • }??


  • ?????這個(gè)類屬于業(yè)務(wù)服務(wù)類,如果用AOP的術(shù)語(yǔ)來(lái)說(shuō),它就是一個(gè)切面類,它定義了許多通知。Before()afterReturn()、after()afterThrowing()這些方法都是通知。

    ?

    下面我們就來(lái)看具體配置,首先來(lái)看一下:

    <1>.基于xml配置文件的AOP實(shí)現(xiàn):這種方式在實(shí)現(xiàn)AOP時(shí),有4個(gè)步驟。

    ?

    [html]?view plaincopy print?
  • <?xml?version="1.0"?encoding="UTF-8"?>??
  • <beans?xmlns="http://www.springframework.org/schema/beans"??
  • ????????xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"??
  • ????????xmlns:aop="http://www.springframework.org/schema/aop"??
  • ????????xsi:schemaLocation="??
  • ????????????http://www.springframework.org/schema/beans?http://www.springframework.org/schema/beans/spring-beans-2.5.xsd??
  • ????????????http://www.springframework.org/schema/aop?http://www.springframework.org/schema/aop/spring-aop-2.5.xsd>??
  • ????<bean?id="registerDaoImpl"?class="com.zxf.dao.RegisterDaoImpl"/>??
  • ????<bean?id="registerService"?class="com.zxf.service.RegisterServiceImpl">??
  • ????????<property?name="?registerDaoImpl?"?ref="?RegisterDaoImpl?"/>??
  • ????</bean>??
  • ????<!--?日志切面類?-->??
  • ????<bean?id="logAspectBean"?class="com.zxf.aspect.LogAspect"/>??
  • ????<!--?第1步:?AOP的配置?-->??
  • ????<aop:config>??
  • ????????<!--?第2步:配置一個(gè)切面?-->??
  • ????????<aop:aspect?id="logAspect"?ref="logAspectBean">??
  • ????????????<!--?第3步:定義切入點(diǎn),指定切入點(diǎn)表達(dá)式?-->??
  • ????????????<aop:pointcut?id="allMethod"???
  • ????????????????expression="execution(*?com.zxf.service.*.*(..))"/>???
  • ????????????<!--?第4步:應(yīng)用前置通知?-->??
  • ????????????<aop:before?method="before"?pointcut-ref="allMethod"?/>??
  • ????????????<!--?第4步:應(yīng)用后置通知?-->??
  • ????????????<aop:after-returning?method="afterReturn"?pointcut-ref="allMethod"/>??
  • ????????????<!--?第4步:應(yīng)用最終通知?-->??
  • ????????????<aop:after?method="after"?pointcut-ref="allMethod"/>??
  • ????????????<!--?第4步:應(yīng)用拋出異常后通知?-->??
  • ????????????<aop:after-throwing?method="afterThrowing"?pointcut-ref="allMethod"/>??
  • ????????????<!--?第4步:應(yīng)用環(huán)繞通知?-->??
  • ????????????<!--??
  • ????????????<aop:around?method="doAround"?pointcut-ref="allMethod"?/>?
  • ?????????????-->??
  • ????????</aop:aspect>??
  • ????</aop:config>??
  • </beans>??

  • ????上述配置針對(duì)切入點(diǎn)應(yīng)用了前置、后置、最終,以及拋出異常后通知。這樣在測(cè)試執(zhí)行RegisterServiceImpl類的save()方法時(shí),控制臺(tái)會(huì)有如下結(jié)果輸出:

    ?

    前置通知:com.zxf.service.RegisterServiceImpl類的save方法開始了。

    針對(duì)MySQL的RegisterDao實(shí)現(xiàn)中的save()方法。

    后置通知:方法正常結(jié)束了。

    最終通知:不管方法有沒(méi)有正常執(zhí)行完成,一定會(huì)返回的。

    下面我們?cè)趤?lái)看一下第二種配置方式:

    <2>基于注解的AOP的實(shí)現(xiàn)

    ?

    ?????首先創(chuàng)建一個(gè)用來(lái)作為切面的類LogAnnotationAspect,同時(shí)把這個(gè)類配置在spring的配置文件中。

    ????????在spring2.0以后引入了JDK5.0的注解Annotation的支持,提供了對(duì)AspectJ基于注解的切面的支持,從而?更進(jìn)一步地簡(jiǎn)化AOP的配置。具體的步驟有兩步。

    ?

    Spring的配置文件是如下的配置:

    ?

    [html]?view plaincopy print?
  • <?xml?version="1.0"?encoding="UTF-8"?>??
  • <beans?xmlns="http://www.springframework.org/schema/beans"??
  • ????????xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"??
  • ????????xmlns:aop="http://www.springframework.org/schema/aop"??
  • ????????xsi:schemaLocation="??
  • ????????????http://www.springframework.org/schema/beans?http://www.springframework.org/schema/beans/spring-beans-2.5.xsd??
  • ????????????http://www.springframework.org/schema/aop?http://www.springframework.org/schema/aop/spring-aop-2.5.xsd>??
  • ????<bean?id="registerDao"?class="com.zxf.dao.RegisterDaoImpl"/>??
  • ????<bean?id="registerService"?class="com.zxf.service.RegisterServiceImpl">??
  • ????????<property?name="registerDao"?ref="registerDao"/>??
  • ????</bean>??
  • ????<!--?把切面類交由Spring容器來(lái)管理?-->??
  • ????<bean?id="logAspectBean"?class="com.zxf.aspect.LogAnnotationAspect"/>??
  • ????<!--?啟用spring對(duì)AspectJ注解的支持?-->??
  • ????<aop:aspectj-autoproxy/>??
  • </beans>??

  • ?

    這是那個(gè)切面的類LogAnnotationAspect

    [java]?view plaincopy print?
  • /**?
  • ?*?日志切面類?
  • ?*/??
  • @Aspect??//定義切面類??
  • public?class?LogAnnotationAspect?{??
  • ????@SuppressWarnings("unused")??
  • ????//定義切入點(diǎn),提供一個(gè)方法,這個(gè)方法的名字就是改切入點(diǎn)的id??
  • ????@Pointcut("execution(*?com.zxf.service.*.*(..))")??
  • ????private?void?allMethod(){}??
  • ????//針對(duì)指定的切入點(diǎn)表達(dá)式選擇的切入點(diǎn)應(yīng)用前置通知??
  • ????@Before("execution(*?com.?zxf.service.*.*(..))")??
  • ????public?void?before(JoinPoint?call)?{??
  • ????????String?className?=?call.getTarget().getClass().getName();??
  • ????????String?methodName?=?call.getSignature().getName();??
  • ????????System.out.println("【注解-前置通知】:"?+?className?+?"類的"???
  • ????????????????+?methodName?+?"方法開始了");??
  • ????}??
  • ????//訪問(wèn)命名切入點(diǎn)來(lái)應(yīng)用后置通知??
  • ????@AfterReturning("allMethod()")??
  • ????public?void?afterReturn()?{??
  • ????????System.out.println("【注解-后置通知】:方法正常結(jié)束了");??
  • ????}??
  • ????//應(yīng)用最終通知??
  • ????@After("allMethod()")??
  • ????public?void?after(){??
  • ????????System.out.println("【注解-最終通知】:不管方法有沒(méi)有正常執(zhí)行完成,"???
  • ????????????????+?"一定會(huì)返回的");??
  • ????}??
  • ????//應(yīng)用異常拋出后通知??
  • ????@AfterThrowing("allMethod()")??
  • ????public?void?afterThrowing()?{??
  • ????????System.out.println("【注解-異常拋出后通知】:方法執(zhí)行時(shí)出異常了");??
  • ????}??
  • ????//應(yīng)用周圍通知??
  • ????//@Around("allMethod()")??
  • ????public?Object?doAround(ProceedingJoinPoint?call)?throws?Throwable{??
  • ????????Object?result?=?null;??
  • ????????this.before(call);//相當(dāng)于前置通知??
  • ????????try?{??
  • ????????????result?=?call.proceed();??
  • ????????????this.afterReturn();?//相當(dāng)于后置通知??
  • ????????}?catch?(Throwable?e)?{??
  • ????????????this.afterThrowing();??//相當(dāng)于異常拋出后通知??
  • ????????????throw?e;??
  • ????????}finally{??
  • ????????????this.after();??//相當(dāng)于最終通知??
  • ????????}??
  • ????????return?result;??
  • ????}??
  • }??

  • ?備注:輸出結(jié)果和前面的一樣。


    from:?http://blog.csdn.net/csh624366188/article/details/7651702

    《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀

    總結(jié)

    以上是生活随笔為你收集整理的Java程序员从笨鸟到菜鸟之(七十四)细谈Spring(六)spring之AOP基本概念和配置详解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。