AOPとは何ですか
AOP(アスペクト指向のプログラミング、アスペクト指向プログラミング)は、OOP(オブジェクト指向プログラミング)の補足と改善であると言えます。 OOPは、カプセル化、相続、多型などの概念を導入して、オブジェクトの階層を確立して、公的行動のコレクションをシミュレートします。散らばったオブジェクトに公共の行動を導入する必要があるとき、OOPは無力に見えます。つまり、OOPを使用すると、上から下への関係を定義できますが、左から右への関係を定義するのに適していません。たとえば、ロギング機能。ログコードは、多くの場合、散乱するオブジェクトのコア機能に関連することなく、すべてのオブジェクトレベルに水平に散在しています。同じことは、セキュリティ、例外処理、透明性など、他のタイプのコードにも当てはまります。どこにでも散在するこの種の無関係なコードは、クロスカットコードと呼ばれます。 OOP設計では、各モジュールの再利用を助長しない多くのコード複製を引き起こします。
それどころか、AOPテクノロジーは「CrossCutting」と呼ばれる手法を使用してカプセル化されたオブジェクトの内部を分析し、複数のクラスに影響を与える共通の動作を再利用可能なモジュールにカプセル化し、「アスペクト」、つまりいわゆる「側面」、つまり、単純に配置することで、コードルが覆われていないビジネスを覆っています。モジュール間の結合を減らし、将来の操作性と保守性を促進します。 AOPは水平な関係を表します。 「オブジェクト」が中空のシリンダーである場合、オブジェクトのプロパティと動作をカプセル化します。次に、アスペクト指向のプログラミング方法は鋭い刃のようなもので、これらの中空シリンダーを切断して内部情報を取得します。カットアウトセクションは、いわゆる「顔」です。次に、痕跡を残さずに、これらのカットアウトセクションを賢い手で復元しました。
「クロスカッティング」テクノロジーを使用して、AOPはソフトウェアシステムを2つの部分に分割します。コアの懸念と相互カットの懸念です。ビジネス処理の主なプロセスは中心的な焦点であり、それとはほとんど関係がない部分は横断的な焦点です。交差懸念の特徴の1つは、それらがしばしば複数のコアの懸念で発生し、基本的にどこでも似ていることです。たとえば、許可認証、ロギング、およびトランザクション処理。 AOPの役割は、システムにおけるさまざまな懸念を分離し、中核的な懸念を相互懸念と分離することです。 AvanadeのシニアソリューションアーキテクトであるAdam Mageeが言ったように、AOPの中心的なアイデアは、「アプリケーションのビジネスロジックをそれをサポートする共通のサービスから分離する」ことです。
AOPを実装するテクノロジーは、主に2つのカテゴリに分かれています。1つは動的プロキシテクノロジーを使用し、メッセージをインターセプトする方法を使用してメッセージを飾る方法を使用して、元のオブジェクトの動作の実行を置き換えることです。もう1つは、静的織り方式を使用して特定の構文を導入して「顔」を作成することです。これにより、コンパイラはコンピレーション中に「顔」に関連するコードを織り込むことができます。
AOP使用シナリオ
AOPは、クロスカットの懸念をカプセル化するために使用されます。これは、次のシナリオで使用できます。
認証権限
キャッシュキャッシュ
コンテンツの渡しコンテンツ
エラー処理
怠zyなロード
デバッグ
ロギング、トレース、プロファイリング、監視
パフォーマンスの最適化
持続性の持続性
リソースプーリング
同期
トランザクション
AOP関連の概念
アスペクト:複数のオブジェクトをさらにクロスカットする可能性のあるフォーカスのモジュール性。トランザクション管理は、J2EEアプリケーションでの相互訴訟の懸念の良い例です。アスペクトは、Springのアドバイザーまたはインターセプターを使用して実装されます。
JoinPoint:メソッドコールやスローされる特定の例外など、プログラムの実行中の明確なポイント。
アドバイス:特定の接続ポイントでAOPフレームワークによって実行されるアクション。さまざまな種類の通知には、「anufer」、「before」、「スロー」通知が含まれます。通知の種類については、以下で説明します。 Springを含む多くのAOPフレームワークは、インターセプターを通知モデルとして使用して、インターセプターチェーンの「ラウンド」接続ポイントを維持します。 4つのアドバイスは春に定義されています:beforeadvice、afteradvice、throwadvice、dynamicintroductionadvice
PointCut:通知がトリガーされる接続ポイントのコレクションを指定します。 AOPフレームワークでは、開発者がエントリポイントを指定できるようにする必要があります。たとえば、正規表現の使用などです。 Springは、MethodMatcherとClassFilterを組み合わせるために使用されるPointCutインターフェイスを定義します。これは、名前を介して明確に理解できます。 MethodMatcherは、ターゲットクラスのメソッドを使用してこの通知を適用できるかどうかを確認するために使用されますが、クラスフィルターはポイントカットをターゲットクラスに適用するかどうかを確認します。
はじめに:通知されたクラスにメソッドまたはフィールドを追加します。 Springを使用すると、通知されたオブジェクトに新しいインターフェイスを導入できます。たとえば、オブジェクトがISModifiedインターフェイスを実装できるようにする紹介を使用して、キャッシュを簡素化できます。春に紹介を使用するには、DelegatingIntroductionInterceptorを使用して通知を実装し、DefaultInTroductionAdvisorを使用してインターフェイスを構成してアドバイスとプロキシクラスを実装できます。
ターゲットオブジェクト:接続ポイントを含むオブジェクト。通知またはプロキシオブジェクトとしても知られています。ポジョ
AOPプロキシ:通知を含むAOPフレームワークによって作成されたオブジェクト。春には、AOPプロキシはJDKダイナミックプロキシまたはCGLIBプロキシになります。
ウィービング:アセンブルして、通知されたオブジェクトを作成します。これは、コンパイル時間(たとえば、AspectJコンパイラを使用)または実行時に実行できます。 Springは、他の純粋なJava AOPフレームワークと同様に、実行時に織りを完了します。
スプリングAOPコンポーネント
次のクラス図には、春のメインAOPコンポーネントがリストされています
Spring AOPの使用方法
スプリングAOPは、構成ファイルまたはプログラミング方法で使用できます。
構成はXMLファイルを介して実行できます。約4つの方法があります。
1. ProxyFactoryBeanを構成し、アドバイザー、アドバイス、ターゲットなどを明示的に設定します。
2。AutoProxyCreatorを構成します。このように、定義された豆は以前と同じように使用されていますが、コンテナから得られるものは実際にはプロキシオブジェクトです。
3。<aop:config>を介して構成します
4。<aop:aspectj-autoproxy>を介して構成し、aspefjアノテーションを使用して通知とエントリポイントを識別します
ProxyFactoryを直接使用して、Spring AOPをプログラムで使用することもできます。 ProxyFactoryが提供するメソッドを介して、ターゲットオブジェクト、アドバイザー、その他の関連する構成を設定し、最後にgetProxy()メソッドを介してプロキシオブジェクトを取得できます。
使用の具体的な例はGoogleです。ここで省略します
スプリングAOPプロキシオブジェクトの生成
Springは、プロキシオブジェクトを生成する2つの方法を提供します:JDKProxyとCGLIB。特定の生成方法は、AdvisedSupportオブジェクトの構成に基づいてAopproxyFactoryによって決定されます。デフォルトのポリシーは、ターゲットクラスがインターフェイスである場合、JDKダイナミックプロキシテクノロジーを使用することです。そうでなければ、CGLIBを使用してプロキシを生成します。 SpringがJDKを使用してプロキシオブジェクトを生成する方法を調べましょう。特定の生成コードはjdkdynamicaopproxyクラスに配置され、関連するコードが直接追加されます。
/** * <ol> * <li>プロキシクラスによってインターフェイスを実装するようにします。アドバイスされたオブジェクトの構成に加えて、SpringProxyも追加され、アドバイス(Opaque = False) * <li>上記のインターフェイスに等しいまたはハッシュコードを定義するインターフェイスがあるかどうかを確認します * <li> proxy.newproxyinstanceを呼び出してプロキシオブジェクト * </ OL> (logger.isdebugenabled()){logger.debug( "JDKダイナミックプロキシの作成:ターゲットソースは" +this.advided.getTargetSource()); } class [] proxiedInterfaces = aopproxyutils.completeproxiedInterfaces(this.Advised); FindDefinedEqualsAndHashCodeMethods(proxiedInterfaces); proxy.newproxyinstance(classloader、proxiedInterfaces、this)を返します。 }その後、これは実際には非常に明確です。私はすでにコメントをはっきりと書いていますが、二度と繰り返されません。
次の質問は、プロキシオブジェクトが生成されますが、カット表面はどのように織り込まれていますか?
InvocationHandlerがJDK Dynamic Proxyのコアであり、生成されたプロキシオブジェクトのメソッド呼び出しは、InvocationHandler.invoke()メソッドに委任されることがわかっています。 Jdkdynamicaopproxyの署名を通じて、このクラスが実際にInvocationHandlerを実装していることがわかります。このクラスで実装されているInvoke()メソッドを分析して、Spring AOPがセクションに織り込む方法を見てみましょう。
publicObject Invoke(Object Proxy、Method Method、Object [] args)throwslowable {MethodInvocation Invocation = null;オブジェクトOldProxy = null; boolean setProxyContext = false; TargetSource TargetSource = this.Advised.TargetSource;クラスターゲットクラス= null;オブジェクトターゲット= null; try {// eqauls()メソッド、ターゲットオブジェクトはこのメソッドを実装しません(!this.equalsdefined && aoputils.isequalsmethod(method)){return(equals(args [0])?boolean.true:boolean.false); } // hashcode()メソッド、ターゲットオブジェクトはこのメソッドを実装しません(!this.hashcodedefined && aoputils.ishcodemethod(method)){return newinteger(hashcode()); } //インターフェイスまたはその親インターフェイスで定義されているメソッドは、通話を直接反映し、通知を使用しません。 aoputils.invokejoinpointusingReflection(this.Advised、Method、args); } object retval = null; if(this.Advised.ExposeProxy){// INVocationを使用可能にする必要があります。 OldProxy = aopcontext.setCurrentProxy(Proxy); SetProxyContext = true; } //ターゲットオブジェクトのクラスターゲットを取得=ターゲットソース.getTarget(); if(ターゲット!= null){ターゲットクラス=ターゲット.getclass(); } //このメソッドに適用できるインターセプターリストを取得しますリストチェーン= this.advided.getInterceptorsandDynamicInterceptionAdvice(Method、TargetClass); //このメソッド(インターセプター)に適用できる通知がない場合、この直接反射コールmethod.Invoke(ターゲット、args)if(chain.isempty()){retval = aoputils.invokejoinpointusingreflection(ターゲット、メソッド、arg); } else {// MethodInvocation Invocation = newRextiveMethodInvocation(Proxy、Target、Method、Args、TargetClass、Chain); retval =招待状.proceed(); } //必要に応じてマッサージ返品値。 if(retval!= null && retval == target && method.getReturnType()。isInstance(proxy)&&!rawTargetAccess.class.class.class.class.(method.getDeclaringclass()){//特別なケース:「this "this"およびmethodの返品タイプ//ターゲットが//それ自体への参照が他に返されたオブジェクトを設定する場合、私たちは助けることができないことに注意してください。 retval = proxy; } return retval; }最後に{if(target!= null &&!targetSource.isstatic()){//は、TargetSourceから来たに違いありません。 TargetSource.ReleaSeTarget(ターゲット); } if(setProxyContext){//古いプロキシを復元します。 aopcontext.setCurrentProxy(OldProxy); }}}主なプロセスは、この方法に適用できる通知チェーンを取得する(インターセプターチェーン)として簡単に説明できます。ある場合は、通知を適用し、JoinPointを実行します。いいえがある場合は、JoinPointを直接反映します。ここで重要なのは、通知チェーンの取得方法と実行方法です。 1つずつ分析しましょう。
まず、上記のコードから、通知チェーンがAdvised.getInterceptorsandDynamicInterceptionAdvice()メソッドを介して取得されることがわかります。この方法の実装を見てみましょう。
public list <object> getinterceptorsanddynamicinterceptionadvice(Method method、class targetclass){methodcachekeycachekey = new MethodCacheKey(Method);リスト<Object> cached = this.methodcache.get(cachekey); if(cached == null){cached = this.advisorchainfactory.getInterceptorsandDynamicInterceptionAdvice(this、method、targetclass); this.methodcache.put(cachekey、cached); } returncached; }実際の買収作業は、実際にAdvisOrchainFactoryによって行われていることがわかります。 getInterceptorsandDynamicInterceptionAdvice()メソッド、および得られた結果はキャッシュされます。
以下のこの方法の実装を分析しましょう。
/***提供されたConfiguration Instance Configからアドバイザーリストを取得し、これらのアドバイザーをトラバースします。 IntroductionAdvisorの場合、 *このアドバイザーをターゲットクラスのターゲットクラスに適用できるかどうかを判断します。 PointCutadvisorの場合は、このアドバイザーをターゲットメソッドメソッドに適用できるかどうかを判断します。条件を満たすアドバイザーは、Advisoradaptorを介してインターセプターリストに変換されます。 */ publicList getInterceptorsandDynamicInterceptionAdvice(Advised Config、MethodMethod、Class TargetClass){//これは難しいことです...最初に紹介を処理する必要があります//しかし、究極のリストに順序を保持する必要があります。 Interceptorlist = new ArrayList(config.getadvisors()。length); //はじめにAdvisor boolean hasintroductions = hasmatchingintroductions(config、targetclass)かどうかを確認します。 //実際、アドバイザーをMethodEnterceptor AdvisorDapterRegistryレジストリに変換するために、一連のAdvisorAdaptersがここに登録されています。 Advisor [] Advisors = config.getadvisors(); for(int i = 0; i <advisors.length; i ++){advisor advisor = advisors [i]; if(advisor instanceof of pointcutadvisor){//条件付きで追加します。 PointCutadvisor PointCutadvisor =(PointCutadvisor)アドバイザー; if(config.isprefiltered()|| pointcutadvisor.getpointcut()。getClassFilter()。一致(ターゲットクラス)){// TODO:これらの2つの方法の位置は、この2つの方法の位置をインターセプターメソジインテルセル[]インターセプター= registertors(アドバイザー); //現在のアドバイザーのポイントカットが現在の方法と一致できるかどうかを確認します。 if(methodmatchers.matches(mm、method、targetclass、hasintroductions)){if(mm.isruntime()){// getInterceptors()メソッドでnewObjectインスタンスを作成する//は問題ではありません。 for(intj = 0; j <interceptors.length; j ++){interceptorlist.add(new interceptoranddynamicmethodmatcher(interceptors [j]、mm)); }} else {interceptorlist.addall(arrays.aslist(interceptors)); }}}} else if(advisor instanceof introdulyadvisor){はじめにadvisor ia =(introllyadvisor)アドバイザー; if(config.isprefiltered()|| ia.getClassFilter()。matches(targetclass)){interceptor [] interceptors = registry.getInterceptors(advisor); InterceptorList.Addall(arrays.aslist(interceptors)); }} else {interceptor [] interceptors = registry.getInterceptors(Advisor); InterceptorList.Addall(arrays.aslist(interceptors)); }} return interceptorlist; }このメソッドが実行された後、接続ポイントまたはターゲットクラスに適用できるアドバイスで構成されたすべてのアドバイザーは、MethodEnterceptorに変換されます。
次に、得られたインターセプターチェーンの仕組みを見てみましょう。
if(chain.isempty()){retval = aoputils.invokejoinpointusingReflection(ターゲット、メソッド、args); } else {// MethodInvocation Invocation = newRextiveMethodInvocation(Proxy、Target、Method、Args、TargetClass、Chain); retval =招待状.proceed(); }このコードから、取得したインターセプターチェーンが空である場合、ターゲットメソッドが直接反映されることがわかります。それ以外の場合、MethodInvocationが作成され、そのプロセス方法が呼び出され、インターセプターチェーンの実行がトリガーされます。特定のコードを見てみましょう
public object ofter()Throws Throwable {// -1およびIncrementのインデックスを早期に開始します。 if(this.currentinterceptorindex == this.interceptorsanddynamicmethodmatchers.size() - 1){//インターセプターの実行が終了した場合、JoinPoint Return invokeJoinPoint(); } object InterceptorInterceptionadvice = this.interceptorsanddynamicmethodmatchers.get(++ this.currentinterceptorindex); // JoinPointを動的に一致させる場合(Interceptor interceptionadvice interceptoranddynamicmethodmatcherのインスタンス){//ここで動的メソッドマッチャーを評価します:静的部分はすでに//マッチングされていることがわかりました。 Interceptoranddynamicmethodmatcher dm =(interceptoranddynamicmethodmatcher)interceptororinterceptionadvice; //ダイナミックマッチ:ランタイムパラメーターがマッチング条件を満たすかどうか(dm.methodmatcher.matches(this.method、this.targetclass、this.arguments)){//現在のintercetpor returndm.interceptor.invoke(this); } else {//動的マッチングが失敗した場合、現在のintercetporをスキップして、次のインターセプター戻り手順()を呼び出します。 }} else {//インターセプターであるため、呼び出すだけです。PointCutwillは、このオブジェクトが構築される前に静的に評価されました。 //現在のintercetpor return((methodinterceptor)interceptororinterceptionadvice).invoke(this)を実行します。 }}コードも比較的単純なので、ここでは詳しく説明しません。
上記はこの記事のすべての内容です。みんなの学習に役立つことを願っています。誰もがwulin.comをもっとサポートすることを願っています。