国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計 > 正文

【spring-boot】spring aop 面向切面編程初接觸

2019-11-14 21:46:53
字體:
供稿:網(wǎng)友
【sPRing-boot】spring aop 面向切面編程初接觸

眾所周知,spring最核心的兩個功能是aop和ioc,即面向切面,控制反轉(zhuǎn)。這里我們探討一下如何使用spring aop。

1.何為aop

  aop全稱aspect Oriented Programming,面向切面,AOP主要實現(xiàn)的目的是針對業(yè)務(wù)處理過程中的切面進(jìn)行提取,它所面對的是處理過程中的某個步驟或階段,以獲得邏輯過程中各部分之間低耦合性的隔離效果。其與設(shè)計模式完成的任務(wù)差不多,是提供另一種角度來思考程序的結(jié)構(gòu),來彌補面向?qū)ο缶幊痰牟蛔恪?/p>

  通俗點講就是提供一個為一個業(yè)務(wù)實現(xiàn)提供切面注入的機制,通過這種方式,在業(yè)務(wù)運行中將定義好的切面通過切入點綁定到業(yè)務(wù)中,以實現(xiàn)將一些特殊的邏輯綁定到此業(yè)務(wù)中。

  比如,若是需要一個記錄日志的功能,首先想到的是在方法中通過log4j或其他框架來進(jìn)行記錄日志,但寫下來發(fā)現(xiàn)一個問題,在整個業(yè)務(wù)中其實核心的業(yè)務(wù)代碼并沒有多少,都是一些記錄日志或其他輔助性的一些代碼。而且很多業(yè)務(wù)有需要相同的功能,比如都需要記錄日志,這時候又需要將這些記錄日志的功能復(fù)制一遍,即使是封裝成框架,也是需要調(diào)用之類的。在此處使用復(fù)雜的設(shè)計模式又得不償失。

  所以就需要面向切面出場了。

3.搭建aop

  本來spring就自帶一套aop實現(xiàn),我們直接使用此實現(xiàn)即可,本來使用aop還需要定義一些xml文件,但由于我們使用的是spring-boot框架,這一步就省略掉了。也就是說,在spring-boot中,我們可以直接使用aop而不需要任何的配置

  具體如何搭建spring-boot請參考:http://m.survivalescaperooms.com/lic309/p/4073307.html

4.aop名稱

  先介紹一些aop的名詞,其實這些名詞對使用aop沒什么影響,但為了更好的理解最好知道一些

  • 切面(Aspect):一個關(guān)注點的模塊化,這個關(guān)注點可能會橫切多個對象。事務(wù)管理是J2EE應(yīng)用中一個關(guān)于橫切關(guān)注點的很好的例子。在Spring AOP中,切面可以使用基于模式或者基于@Aspect注解的方式來實現(xiàn)。

  • 連接點(Joinpoint):在程序執(zhí)行過程中某個特定的點,比如某方法調(diào)用的時候或者處理異常的時候。在Spring AOP中,一個連接點總是表示一個方法的執(zhí)行。

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

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

  • 引入(Introduction):用來給一個類型聲明額外的方法或?qū)傩裕ㄒ脖环Q為連接類型聲明(inter-type declaration))。Spring允許引入新的接口(以及一個對應(yīng)的實現(xiàn))到任何被代理的對象。例如,你可以使用引入來使一個bean實現(xiàn)IsModified接口,以便簡化緩存機制。

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

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

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

其中重要的名詞有:切面,切入點

 5.簡單例子:

    可能直接說會很模糊,這里我先做了一個小例子:直接上代碼

    

//描述切面類@Aspect@Configurationpublic class TestAop {    /*     * 定義一個切入點     */    // @Pointcut("execution (* findById*(..))")    @Pointcut("execution(* com.test.service.CacheDemoService.find*(..))")    public void excudeService(){}    /*     * 通過連接點切入     */    @Before("execution(* findById*(..)) &&" + "args(id,..)")    public void twiceAsOld1(Long id){        System.err.println ("切面before執(zhí)行了。。。。id==" + id);    }    @Around("excudeService()")    public Object twiceAsOld(ProceedingJoinPoint thisJoinPoint){        System.err.println ("切面執(zhí)行了。。。。");        try {            Thing thing = (Thing) thisJoinPoint.proceed ();            thing.setName (thing.getName () + "=========");            return thing;        } catch (Throwable e) {            e.printStackTrace ();        }        return null;    }}

  看上面的例子就是實現(xiàn)了一個切面,其中有一些特殊的東西,下面一一解釋:

6.使用的注解:

  @Aspect:描述一個切面類,定義切面類的時候需要打上這個注解

   @Configuration:spring-boot配置類

   1. @Pointcut:聲明一個切入點,切入點決定了連接點關(guān)注的內(nèi)容,使得我們可以控制通知什么時候執(zhí)行。Spring AOP只支持Spring bean的方法執(zhí)行連接點。所以你可以把切入點看做是Spring bean上方法執(zhí)行的匹配。一個切入點聲明有兩個部分:一個包含名字和任意參數(shù)的簽名,還有一個切入點表達(dá)式,該表達(dá)式?jīng)Q定了我們關(guān)注那個方法的執(zhí)行。

  注:作為切入點簽名的方法必須返回void類型

  Spring AOP支持在切入點表達(dá)式中使用如下的切入點指示符:    

    • execution- 匹配方法執(zhí)行的連接點,這是你將會用到的Spring的最主要的切入點指示符。

    • within- 限定匹配特定類型的連接點(在使用Spring AOP的時候,在匹配的類型中定義的方法的執(zhí)行)。

    • this- 限定匹配特定的連接點(使用Spring AOP的時候方法的執(zhí)行),其中bean reference(Spring AOP 代理)是指定類型的實例。

    • target- 限定匹配特定的連接點(使用Spring AOP的時候方法的執(zhí)行),其中目標(biāo)對象(被代理的應(yīng)用對象)是指定類型的實例。

    • args- 限定匹配特定的連接點(使用Spring AOP的時候方法的執(zhí)行),其中參數(shù)是指定類型的實例。

    • @target- 限定匹配特定的連接點(使用Spring AOP的時候方法的執(zhí)行),其中正執(zhí)行對象的類持有指定類型的注解。

    • @args- 限定匹配特定的連接點(使用Spring AOP的時候方法的執(zhí)行),其中實際傳入?yún)?shù)的運行時類型持有指定類型的注解。

    • @within- 限定匹配特定的連接點,其中連接點所在類型已指定注解(在使用Spring AOP的時候,所執(zhí)行的方法所在類型已指定注解)。

    • @annotation- 限定匹配特定的連接點(使用Spring AOP的時候方法的執(zhí)行),其中連接點的主題持有指定的注解。

其中execution使用最頻繁,即某方法執(zhí)行時進(jìn)行切入。定義切入點中有一個重要的知識,即切入點表達(dá)式,我們一會在解釋怎么寫切入點表達(dá)式。

   切入點意思就是在什么時候切入什么方法,定義一個切入點就相當(dāng)于定義了一個“變量”,具體什么時間使用這個變量就需要一個通知。

   即將切面與目標(biāo)對象連接起來。

  如例子中所示,通知均可以通過注解進(jìn)行定義,注解中的參數(shù)為切入點。

  spring aop支持的通知:

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

  @AfterReturning :后置通知:在某連接點正常完成后執(zhí)行的通知,通常在一個匹配的方法返回的時候執(zhí)行。

      可以在后置通知中綁定返回值,如:        

@AfterReturning(    pointcut=com.test.service.CacheDemoService.findById(..))",    returning="retVal")  public void doFindByIdCheck(Object retVal) {    // ...  }

   @AfterThrowing:異常通知:在方法拋出異常退出時執(zhí)行的通知?!      ?/p>

   @After 最終通知。當(dāng)某連接點退出的時候執(zhí)行的通知(不論是正常返回還是異常退出)。

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

      環(huán)繞通知最麻煩,也最強大,其是一個對方法的環(huán)繞,具體方法會通過代理傳遞到切面中去,切面中可選擇執(zhí)行方法與否,執(zhí)行方法幾次等。

      環(huán)繞通知使用一個代理ProceedingJoinPoint類型的對象來管理目標(biāo)對象,所以此通知的第一個參數(shù)必須是ProceedingJoinPoint類型,在通知體內(nèi),調(diào)用ProceedingJoinPointproceed()方法會導(dǎo)致后臺的連接點方法執(zhí)行。proceed方法也可能會被調(diào)用并且傳入一個Object[]對象-該數(shù)組中的值將被作為方法執(zhí)行時的參數(shù)。

7.通知參數(shù)

  任何通知方法可以將第一個參數(shù)定義為org.aspectj.lang.JoinPoint類型(環(huán)繞通知需要定義第一個參數(shù)為ProceedingJoinPoint類型,它是JoinPoint的一個子類)。JoinPoint接口提供了一系列有用的方法,比如getArgs()(返回方法參數(shù))、getThis()(返回代理對象)、getTarget()(返回目標(biāo))、getSignature()(返回正在被通知的方法相關(guān)信息)和toString()(打印出正在被通知的方法的有用信息)

  有時候我們定義切面的時候,切面中需要使用到目標(biāo)對象的某個參數(shù),如何使切面能得到目標(biāo)對象的參數(shù)。

  從例子中可以看出一個方法:

  使用args來綁定。如果在一個args表達(dá)式中應(yīng)該使用類型名字的地方 使用一個參數(shù)名字,那么當(dāng)通知執(zhí)行的時候?qū)?yīng)的參數(shù)值將會被傳遞進(jìn)來。

  

 @Before("execution(* findById*(..)) &&" + "args(id,..)")    public void twiceAsOld1(Long id){        System.err.println ("切面before執(zhí)行了。。。。id==" + id);    }

    

@Around("execution(List<Account> find*(..)) &&" +        "com.xyz.myapp.SystemArchitecture.inDataaccessLayer() && " +        "args(accountHolderNamePattern)")        public Object preProcessQueryPattern(ProceedingJoinPoint pjp, String accountHolderNamePattern)throws Throwable {  String newPattern = preProcess(accountHolderNamePattern);  return pjp.proceed(new Object[] {newPattern});}        

8.切入點表達(dá)式

  現(xiàn)在我們介紹一下最重要的切入點表達(dá)式:

  如上文所說,定義切入點時需要一個包含名字和任意參數(shù)的簽名,還有一個切入點表達(dá)式,就是* findById*(..)這一部分。

  切入點表達(dá)式的格式:execution([可見性] 返回類型 [聲明類型].方法名(參數(shù)) [異常])

  其中【】中的為可選,其他的還支持通配符的使用:

  *:匹配所有字符 ..:一般用于匹配多個包,多個參數(shù) +:表示類及其子類

  運算符有:&&、||、!

  

切入點表達(dá)式關(guān)鍵詞:

  1)execution:用于匹配子表達(dá)式。

//匹配com.cjm.model包及其子包中所有類中的所有方法,返回類型任意,方法參數(shù)任意 @Pointcut("execution(* com.cjm.model..*.*(..))") public void before(){}

2)within:用于匹配連接點所在的Java類或者包。

//匹配Person類中的所有方法 @Pointcut("within(com.cjm.model.Person)") public void before(){}

//匹配com.cjm包及其子包中所有類中的所有方法

@Pointcut("within(com.cjm..*)") public void before(){}

3) this:用于向通知方法中傳入代理對象的引用。 @Before("before() && this(proxy)") public void beforeAdvide(JoinPoint point, Object proxy){ //處理邏輯 }

4)target:用于向通知方法中傳入目標(biāo)對象的引用。 @Before("before() && target(target) public void beforeAdvide(JoinPoint point, Object proxy){ //處理邏輯 }

5)args:用于將參數(shù)傳入到通知方法中。 @Before("before() && args(age,username)") public void beforeAdvide(JoinPoint point, int age, String username){ //處理邏輯 }6)@within:用于匹配在類一級使用了參數(shù)確定的注解的類,其所有方法都將被匹配。

@Pointcut("@within(com.cjm.annotation.AdviceAnnotation)") - 所有被@AdviceAnnotation標(biāo)注的類都將匹配 public void before(){}

  

7)@target:和@within的功能類似,但必須要指定注解接口的保留策略為RUNTIME。 @Pointcut("@target(com.cjm.annotation.AdviceAnnotation)") public void before(){}

8)@args:傳入連接點的對象對應(yīng)的Java類必須被@args指定的Annotation注解標(biāo)注。 @Before("@args(com.cjm.annotation.AdviceAnnotation)") public void beforeAdvide(JoinPoint point){ //處理邏輯 }

  

9)@annotation:匹配連接點被它參數(shù)指定的Annotation注解的方法。也就是說,所有被指定注解標(biāo)注的方法都將匹配。 @Pointcut("@annotation(com.cjm.annotation.AdviceAnnotation)") public void before(){}

10)bean:通過受管Bean的名字來限定連接點所在的Bean。該關(guān)鍵詞是Spring2.5新增的。 @Pointcut("bean(person)") public void before(){}

 9.參考資料

    http://blog.csdn.net/yuqinying112/article/details/7244281

    http://www.2cto.com/kf/201204/128280.html

    http://blog.csdn.net/archie2010/article/details/6254343

    

    


發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 乌鲁木齐市| 仁化县| 醴陵市| 德昌县| 涟源市| 仁怀市| 龙海市| 洛隆县| 察雅县| 白河县| 马尔康县| 江达县| 乡城县| 永福县| 石狮市| 乌兰浩特市| 田东县| 集安市| 小金县| 襄垣县| 城口县| 西乡县| 寻乌县| 灵台县| 昆山市| 七台河市| 郸城县| 柳江县| 阳东县| 新丰县| 如东县| 房产| 岳普湖县| 汾西县| 泾川县| 延吉市| 靖安县| 安溪县| 阿拉善右旗| 泊头市| 读书|