スプリングAOP通知は、5つのカテゴリに分かれています。
アドバイスの前:接続ポイントの前で実行します。プレビューは、ここに例外がスローされない限り、接続ポイントの実行に影響しません。
通常の返品通知[アドバイスを返した後]:接続ポイントの通常の実行後に実行が完了します。例外が接続ポイントによってスローされた場合、実行されません。
例外返品通知[アドバイスを投げた後]:例外が接続ポイントによってスローされた後に実行します。
[(最終的に)アドバイス後]返信通知:実行が完了した後、返品通知の内容が正常に完了するか例外がスローされているかどうかにかかわらず実行されます。
アドバイスについて:メソッド呼び出しの前後など、接続ポイントを取り巻くアドバイスを中心に。これは最も強力な通知タイプであり、メソッド呼び出しの前後の操作をカスタマイズできます。
また、周囲の通知は、結合ポイントの処理を続行するか(ProceedJoinPointのプロセスメソッドを呼び出す)か、実行を中断するかを決定する必要があります。
次に、サンプルプログラムを作成して、5つの通知タイプをテストします。
インターフェイスを定義します
パッケージcom.chenqa.springaop.example.service; public interface bankservice { / *** simulated bank transfer* @param from Account* @param to Account* @paramアカウント転送額* @return* / public boolean transfer(string to、doubleアカウント);}実装クラスを作成します
パッケージcom.chenqa.springaop.example.service.impl;インポートcom.chenqa.springaop.example.service.bankservice;パブリッククラスBCMBANKSERVICEIMPLはBankservice {Public Boolean Transfer(String Form、String to、Double Account){If yuan "); } system.out.println(form+"Transfer"+to+"Bank Account"+"Yuan"); falseを返します。 }}Spring構成ファイルを変更し、以下を追加します。
<! - bankservice bean - > <bean id = "bankservice"/> <! - section-> <bean id = "myaspect"/> <! - > <aop:config> <aop:aspect ref = "myaspect"> <aop:pointcut expression = "execution(*com.chenqa.springaop.example。 id = "pointcut"/> <aop:before method = "before" pointcut-ref = "point-cut"/> <aop:after "pointcut-ref =" point-cut "/> <aop:a after-returning method =" after returning "pointcut-ref =" point-cut "/>> <a after-lowing" point-cutowing "/> <aop:method = "around" pointcut-ref = "pointcut"/> </aop:aspect> </aop:config>
テストプログラムの作成
ApplicationContext Context = new ClassPathXMLApplicationContext( "Spring-aop.xml"); Bankservice bankservice = context.getBean( "Bankservice"、bankservice.class); Bankservice.Transfer( "Zhang San"、 "Li Si"、200);
実行後の出力:
テストプログラムの200を50に変更し、実行後に出力します。
テスト結果から、5つの通知の実行順序は次のとおりです。
事前通知→サラウンド通知→通常の返品通知/例外返品通知→返品通知、表示するために複数回実行できます。
ケース1:メソッドは1つのアスペクトクラスによってのみ傍受されます
メソッドが1つの側面のみによって傍受される場合、この側面のさまざまなアドバイスはどのような順序で実行されますか?参照してください:
ポイントカットクラスを追加します
このポイントカットは、テストパッケージの下ですべてのクラスのすべてのメソッドを傍受するために使用されます。
パッケージテスト; import org.aspectj.lang.annotation.pointcut; public class pointcuts {@pointcut(value = "内(test。*)")public void aopdemo(){}}アスペクトクラスを追加します
このクラスのアドバイスは、上記のポイントカットを使用します。それを使用するときは、各アドバイスの値属性を参照してください。
パッケージテスト; Import org.aspectj.lang.joinpoint; import org.aspectj.lang.proceedjoinpoint; import org.aspectj.lang.annotation。 {system.out.println( "[aspect1] beforeアドバイス"); } @Around(value = "test.pointcuts.aopdemo()")public void oursive(proceedingjoinpoint pjp)throws throws {system.out.println( "[aspect1] andubs absive 1"); pjp.proceed(); system.out.println( "[aspect1] oursion abuse2"); } @afterturning(value = "test.pointcuts.aopdemo()")public void afterreturning(joinpoint joinpoint){system.out.println( "[aspect1] afterreturning advige"); } @afterthrowing(value = "test.pointcuts.aopdemo()")public void andthrowing(joinpoint joinpoint){system.out.println( "[aspect1] shovthering advies"); } @after(value = "test.pointcuts.aopdemo()")public void affery(joinpoint joinpoint){system.out.println( "[aspect1] shovthrowing advies"); } @after(value = "test.pointcuts.aopdemo()")public void after(joinpoint joinpoint){system.out.println( "[aspect1] after bodis"); }}テストコントローラーを追加します
テスト用のコントローラーを追加します。このコントローラーには1つのメソッドのみがありますが、パラメーター値に応じて異なる方法で処理します。1つは通常、オブジェクトを返すことであり、もう1つは例外をスローすることです(@AfterThrowingアドバイスをテストしたいので)
パッケージテスト; Import test.exception.testexception; import org.springframework.http.httpstatus; import org.springframework.web.bind.annotation。 = "/test"、method = requestmethod.get)public result test(@requestparam boolean throwexception){// case 1 if(throwexception){system.out.println( "shrow an例外");新しいtestexception( "mock a server Exception"); } //ケース2 System.out.println( "test ok"); return new result(){{this.setId(111); this.setname( "mock a result"); }}; } public static class result {private int id;プライベート文字列名; public int getid(){return id; } public void setid(int id){this.id = id; } public string getname(){return name; } public void setName(string name){this.name = name; }}}通常の状況をテストします
次のURLをブラウザに直接入力して、 http://192.168.142.8:7070/aoptest/v1/aop/test?throwException=false ://192.168.142.8:7070/aoptest/v1/aop/test?throwexception=false 1
出力の結果が表示されます。
[Aspect1]アドバイス1 [Aspect1]アドバイスの前にOK [Aspect1] About Advide2 [Aspect1] After Advise [Aspect1] AfterReturning Advies
テストの例外
ブラウザで次のURLを直接入力し、Enterを押します: http://192.168.142.8:7070/aoptest/v1/aop/test?throwException=true 7070/aoptest/v1/aop/test?throwexception=true 1
出力の結果が表示されます。
[Aspect1]アドバイスについて1 [aspet1]アドバイスをアドバイスする前に[Aspect1]アドバイスの後に[Aspect1]アドバイス後へ
結論は
メソッドが1つのアスペクトクラスのみで傍受されると、アスペクトクラス内のアドバイスは次の順序で実行されます。
通常の状況:
例外:
ケース2:同じ方法が複数のアスペクトクラスによって傍受されます
2つのアスペクトクラスによって傍受される例を以下に示します。
場合によっては、2つの異なるアスペクトクラスの場合、アドバイスが同じポイントカットまたは異なるポイントカットを使用するかどうかに関係なく、複数のアスペクトクラスによって同じ方法が傍受される可能性があります。したがって、この場合、これらの複数のアスペクトクラスのアドバイスはどのような順序で実行されますか?参照してください:
ポイントカットクラスは変更されていません
新しいアスペクトクラスを追加します
パッケージテスト; aspectj.lang.joinpoint; Import org.aspectj.lang.proceedjoinpoint; import org.aspectj.lang.annotation。 {system.out.println( "[aspect2] beforeアドバイス"); } @around(value = "test.pointcuts.aopdemo()")public void oursive(proceedingjoinpoint pjp)throws throws {system.out.println( "[aspect2] andove about advise 1"); pjp.proceed(); system.out.println( "[aspect2] reduver advide2"); } @afterturning(value = "test.pointcuts.aopdemo()")public void afterreturning(joinpoint joinpoint){system.out.println( "[aspect2] afterreturning advieg"); } @afterthrowing(value = "test.pointcuts.aopdemo()")public void andthrowing(joinpoint joinpoint){system.out.println( "[aspect2] shovtholing advies"); } @after(value = "test.pointcuts.aopdemo()")public void after(joinpoint joinpoint){system.out.println( "[aspect2] shopthowing advies"); } @after(value = "test.pointcuts.aopdemo()")public void affery(joinpoint joinpoint){system.out.println( "[aspect2] aby absis"); }}テストコントローラーも変更されていません
上記のコントローラーを使用してください。しかし、現在、Aspect1とAspect2の両方がコントローラーのメソッドを傍受します。
以下をテストし続けてください!
通常の状況をテストします
次のURLをブラウザに直接入力して、 http://192.168.142.8:7070/aoptest/v1/aop/test?throwException=false ://192.168.142.8:7070/aoptest/v1/aop/test?throwexception=false 1
出力の結果が表示されます。
[aspect2]アドバイス1 [asept2]アドバイスの前のアドバイスの前の[aspect1]アドバイスの前のアドバイスの前の[asped1] advide2 [asped1] aftion aftifis aftion 2 [asepe1] advide [aspet2] anduction2 [aspet2] andaver returning advie
しかし、現時点では、Aspect2がAspect1よりも間違いなく実行されると結論付けることはできません。
信じられない?サーバーを再起動して再試行してください。おそらく、次の実行結果が表示されます。
アドバイスの前のアドバイスの前のアドバイスの前のアドバイスの前のアドバイスの前のアドバイスの前のアドバイスの前のアドバイスの前の[aspet2] advide2]アドバイスの後の[aspet2] aspect2] advide [aspet1] returturne
つまり、この場合、Aspect1とaspet2の実行順序は不明です。それで、それを解決する方法は?急いでは、ソリューションを以下に示します。
テストの例外
ブラウザで次のURLを直接入力し、Enterを押します: http://192.168.142.8:7070/aoptest/v1/aop/test?throwException=true 7070/aoptest/v1/aop/test?throwexception=true 1
出力の結果が表示されます。
[Aspect2]アドバイスを中心にアドバイスの前のアドバイスの前に[Aspect1]アドバイスをアドバイスする前のアドバイス1 [Aspect1]アドバイスを投げた後、アドバイスを投げた後[Aspect1]
同様に、サーバーを再起動してから再度テストすると、次の結果が表示されます。
アドバイスを中心にアドバイスの前のアドバイスの前の[aspect2]アドバイスについて1 [aspet2]例外をアドバイスする前に[aspet2]アドバイスを後投げている[asped1]後投げアドバイスを
つまり、同様に、Aspect1とAspect2の実行順序も例外的な状況では未定です。
ケース2では、各側面の実行順序をどのように指定しますか?
2つの方法があります。
どの方法を使用しても、アスペクトが小さくなるほど、最初に実行されます。
たとえば、次のように、それぞれapsect1とaspect2に@orderアノテーションを追加します。
@Order(5)@component@saspepublic class aspect1 {// ...}@order(6)@component@asdeppublic class asepe2 {// ...}この変更の後、いずれにせよ、Aspect1のアドバイスが常にAspect2のアドバイスの前に実行されることを保証できます。下の図に示すように:
注記
同じポイントカット(たとえば、2つの@before)に対して2つの同一のアドバイスが定義されている場合、これら2つのアドバイスに@Orderアノテーションを追加しても、これら2つのアドバイスの実行命令を決定できません。これを覚えておいてください。
@Aroundのアドバイスについては、返品値があるかどうかに関係なく、メソッド内でpjp.proceed()を呼び出す必要があります。それ以外の場合、コントローラー内のインターフェイスは実行されません。これにより、@BeForeアドバイスがトリガーされません。たとえば、通常の状況では、実行順序は「aspect2-> apsect1->コントローラー」であると想定しています。 pjp.proceed()を削除する場合; Aspect1の@Aroundでは、表示される出力は次のとおりです。
[Aspect2]アドバイス1 [Aspect2]アドバイスの前の[Aspect1]アドバイスについて1 [Aspect1] About Advide2 [Aspect1] After Advide [Aspect1] After Returning Advide [Aspect2] Advide2 [Aspect2] After Returning Advief
結果から、コントローラーのインターフェイスが実行されておらず、Aspect1の@beforeadviceも実行されていないことがわかります。
上記はこの記事のすべての内容です。みんなの学習に役立つことを願っています。誰もがwulin.comをもっとサポートすることを願っています。