AndroidでAOPカットプログラミングを実現

5415 ワード

仲間たちはjavaの基礎を学ぶとき、必ず対象思想と3つの特性を学ぶに違いない.OOP設計には単一の職責原則があり、多くの場合問題はありませんが、多くのモジュールが同じ機能を必要とする場合、このときOOPを使うのは面倒です.たとえば、各モジュールにlogを印刷したいので、logクラスCustomLogクラスを書き、必要な場所にlogコードを書きますが、モジュール間の侵入が深すぎて、モジュール間の結合が大幅に増加します.この時、AOPカットプログラミングについて知ることができます.AOPはAspect-Oriented Progremingの略で、同じ種類の問題に対する統一処理を提唱し、プリコンパイル方式とランタイム動的エージェントによってプログラム機能の統一メンテナンスを実現する技術である.AOPはOOPの継続であり、ソフトウェア開発におけるホットスポットであり、Springフレームワークにおける重要な内容でもあり、関数式プログラミングの派生モデルである.AOPを利用してビジネスロジックの各部分を隔離することができ、それによってビジネスロジックの各部分間の結合度を低下させ、プログラムの再利用性を高め、同時に開発の効率を高めた.これに基づいて、AOPのAndroidでの応用が生まれた.AOP特性に基づいて,android開発におけるフェースプログラミングの非常に多くの応用シーン,例えば無感埋め込み点を自然に考えることができ,埋め込み点のコードが汎用的であるため,@HookMethod注釈を埋め込み点にカスタマイズすることができる.非同期注釈をカスタマイズして、サブスレッドにメソッドを配置して実行することもできます.エアバッグを作成し、APPの安定性を保障するためにも使用できます.同社がAPPの崩壊率をさらに下げる要求に応じて、AOP切面プログラミングを使用してアプリケーションに親切な保護o(′▽`)oを追加することにした.
AspectJ
OOPのJavaのように、一部の先行者もAOPをサポートするために何かをしました.今使っているのはAspectJです.実際には新しい言語ではなく、コードコンパイラであり、Javaコンパイラに基づいて独自のキーワード識別とコンパイル方法を追加しました.したがってajcはJavaコードをコンパイルすることもできる.もちろん、AspectJの特殊なキーワードを使う以外は、対応するAspectJ注釈を付ければよい.AspectJのAndroid Studioでの構成はここでは説明しませんが、興味のある仲間はここを見てもいいです.私のこの文章もここから参考にしています.
基礎概念
Aspect切面:cross-cutting機能を実現し、切面に対するモジュールです.最も一般的なのはloggingモジュール、メソッド実行時間のかかるモジュールです.このように、プログラムは機能によっていくつかの層に分けられています.従来の継承では、ビジネスモデル継承ログモジュールでは修正を挿入する必要がありますが、1つの接面を作成することでAOPを使用して同じ機能を実現することができ、異なるニーズに対して異なる接面を行うことができます.
Pointカットポイント:pointcutは、jointpointにどのadviceを適用するかを制御します.通常、pointcutsを使用して正規表現で明らかな名前とモードをマッチングします.そのjointpointが通知を受けることが決まった.call、execution、target、this、withinなどのキーワードに分けられます(具体的な意味は第4節を参照).
Advice通知:adviceは私たちの接面機能の実現であり、それは接点の本当の実行場所である.たとえば、ファイルにログを書くように、advice(before、after、aroundなどを含む)はjointpointにコードをアプリケーションに挿入します.元のAspectJプログラムと逆コンパイル後のプログラムを見てみましょう.次の図を見て、AspectJがソースプログラムを監視する情報をどのように達成したかがわかります.
Joint Point接続点:接続点は、メソッドによって呼び出され、予期せぬものが投げ出される接面挿入アプリケーションの場所です.接続点は、アプリケーションが接面挿入に提供する場所であり、挿入地にAspectJプログラムとソースプログラムとの接続を確立する.
Weaving編み:主にコンパイル期間にAJCを用いて切面のコードをターゲットに注入し、コード混合を生成する.classのプロセス
フェースプログラミングを実行したい場合は、まず切り込み点を見つけます.つまり、操作されるオブジェクトを見つけ、PointCutでフィルタリングし、切り込み点を見つけます.切り込みポイントを見つけたら、フェースプログラミングの実行タイミングを決定する必要があります.この場合、Adviceに通知する必要があります.以下、詳しく見てみましょう.
@Aspect//  AspectJ  
public class MMHSafeAspect {
     //    ,                
    //synthetic              ,   
    @Around("execution(!synthetic * *(..)) && onSafe()")
    public Object doSafeMethod(final ProceedingJoinPoint joinPoint) throws Throwable {
        return safeMethod(joinPoint);
    }

    //            
    //CrashSafe      ,    CrashSafe            
    @Pointcut("@within(  .CrashSafe)||@annotation(  .CrashSafe)")
    public void onSafe() {
    }

    private Object safeMethod(final ProceedingJoinPoint joinPoint) throws Throwable {
        Object result = null;
        try {
            //          ,    try_catch,         
            result = joinPoint.proceed(joinPoint.getArgs());
        } catch (Throwable e) {
            Log.e("MMHSafeAspect", "        ", e);
            if(null != AopApplicationContext.getInstacne()){
                AopApplicationContext.getInstacne().postBugly(e);
                if(BuildConfig.DEBUG){
                    BugTipActivity.startBugTip(Log.getStackTraceString(e));
                }
            }
        }
        return result;
    }
}

上はエアバッグのコアコードで、私たちは一反三を挙げて、自分でいくつかの基本的なデータ構造を構築することができて、そしてエアバッグの保護を採用します.Javaレイヤcrashを大幅に削減する目的を達成します.もちろん、これはユーザー体験を増やす手段にすぎません.この方法で問題を回避することはできないので、debugモードで問題を暴露し、オンラインバージョンでエアバッグを有効にする必要があります.テーマに戻ると、Aspect、executionなどのキーワードに慣れていないかもしれません.焦らないでください.次はゆっくり話します.
キーワード
Aspect:ここでAspectを使用するコンパイラをコンパイルするには、クラスにexecutionをマークする必要があります.名前の通り、メソッドが実際に実行されるコード領域をキャプチャし、Aroundメソッドブロックはそれのために特別に存在します.Aroundを呼び出すと、元のメソッドの実行を制御するか、実行するか置換するかを選択できます.これと同様にcallもあり、名前から分かるように、callがキャプチャしたのはメソッドの呼び出し領域であり、コードの真の実行領域はキャプチャされず、メソッド呼び出しの前と呼び出しの後(before、afterと組み合わせて使用される)をキャプチャし、呼び出し方法の前後にJoinPointとbefore、after通知を挿入する.キャプチャされた情報はexecutionほど多くなく、元のメソッドの実行の有無を制御できず、メソッド呼び出しの前後に接点を挿入するだけなので、軽量なモニタリング(メソッド呼び出しに時間がかかり、メソッドの戻り値など)に適しています.Around:ターゲットメソッドボディがAroundメソッドに置き換えられ、元のメソッドが再生成されます.XXX_AroundBody()は、元のメソッドを呼び出すにはAspectJプログラムのAroundメソッド内でjoinPointを呼び出す必要がある.Proceed()復元メソッドは、元のメソッドを置き換える目的で実行されます.この目的を達成するには双方が相互に参照する必要があり,ブリッジはAspectクラスであり,ターゲットプログラムはAspectクラスが存在するパケットを挿入して参照を取得する.AspectJは,ターゲットクラスインスタンス,ターゲットメソッドパラメータ,JoinPointオブジェクトなどの情報を含むクラスをターゲットクラスに組み込むことにより,Aspectクラス呼び出しAroundメソッドによりAspectプログラムに伝達される接点元メソッドの実行エージェントとして扱う.これにより関連する目的が達成され,Aspectプログラムでターゲットプログラムを監視し修正することができる.BeforeとAfter:BeforeとAfterは、メソッドが呼び出される前と呼び出された後にJoinPointと通知メソッド(元のプログラムメソッドボディに直接挿入)を追加するだけで、AspectJプログラム定義のAdviseメソッドを呼び出す.元のメソッドに代わるものではなく、メソッドcallの前と後に挿入操作を行う.Afterはreturnningとthrowingの2種類に分けられ、前者は通常のreturningの後に呼び出され、後者はthrowingが発生した後に呼び出される.デフォルトのAfterはfinallyで呼び出されるため、前の2つのケースが含まれています.その他の一般的なキーワードは、this:現在のAOPエージェントオブジェクトタイプに一致する実行方法です.AOPエージェントオブジェクトのタイプマッチングであることに注意してください.これにより、インタフェースの導入もタイプマッチングも含まれる可能性があります.target:現在のターゲットオブジェクトタイプに一致する実行方法.ターゲットオブジェクトのタイプマッチングであることに注意してください.これにより、インタフェースの導入もタイプマッチングも含まれません.args:現在実行されているメソッドに一致するパラメータが指定されたタイプの実行メソッドである.within:指定したタイプ内のメソッドの実行に一致します.
使用方法
1.カスタム注釈と組み合わせて上記のコードを使用すると、execution、callで注釈を使用でき、ターゲットメソッドで注釈を使用して関連付け、キャプチャできます.このような欠点はソースコードに侵入して、いくつかの軽量な操作ができます.利点は柔軟性2.直接使用、すなわち直接切り込み点を書くという欠点は、範囲が広すぎることです.もし私たちがすべてのactivityのすべての方法を切り込み点に設定したら、非常に性能を損なうのではないでしょうか.ビジネスニーズに合わせて適切な使い方を選ぶことができます.仕事が終わったので,続けて書く時間がある.