Spring AOP基本概念


テキストリンク:http://remcarpediem.net/2019/02/08/Spring-AOP-%E4%B8%80-AOP%E5%9F%BA%E6%9C%AC%E6%A6%82%E5%BF%B5/
なぜAOPを使うのか
AOPはAspect-oriented programmingの略で、接面向けのプログラミングを意味し、オブジェクト向けプログラミング(OOP)への補完である.AOPの概念を理解するためには、まずAOPがどのような問題を解決するためなのかを理解する必要があります.
システムにはクロストラフィックが存在し、1つのトラフィックはシステムの1つの側面に切り込むことである.たとえば、セキュリティ、トランザクション、ログなどの機能は、複数のモジュールに貫かなければならないので、クロスビジネスです.Spring AOP 基本概念_第1张图片 AOPの目標はクロストラフィックをモジュール化し,モジュール化してクロストラフィックをスライス(Aspect)することである.Spring AOP 基本概念_第2张图片には、フェース向けプログラミングとは何かがよく説明されています.AOPフレームワークは、クロストラフィックコードを1部書くだけで、他の場所はすべて自動的に適用され、すべての場所で重複したコードを書く必要はありません.AOP , 。原文リンク
AOP実装の鍵はAOPフレームワークによって自動的に作成されるAOPエージェントであり,AOPエージェントは主に静的エージェントと動的エージェントに分けられる.本文は主にAOPの基本的な用語を説明して、それから1つの例でみんなにこれらの名詞を徹底的に理解させて、最後にAOPの2種類の代理方式を紹介します:
AspectJに代表される静的エージェント.Spring AOPに代表される動的エージェント.
基本用語
(1)切面(Aspect)
スライスは、トランザクションとログ処理の2つのスライスとして理解できるように、同じタイプの異なる拡張方法を含む横断的な注目点のモジュール化です.接面は、横断論理の定義と接点の定義を含む接点と通知から構成されます.Spring AOPは、切断面を実装するフレームワークであり、切断面で定義された横断論理を切断面で指定された接続点に織り込む.
@Component
@Aspect
public class LogAspect {
}

@Aspect注釈を用いたクラスが切面であると簡単に考えられる.
(2)ターゲットオブジェクト(Target)
ターゲット・オブジェクトとは、拡張されるオブジェクト、すなわちプライマリ・ビジネス・ロジックを含むクラス・オブジェクトを指します.あるいは、1つまたは複数の接面によって通知されたオブジェクトである.
(3)接続点(JoinPoint)
プログラム実行中に明確な点、例えば方法の呼び出しや特定の異常が投げ出される.接続ポイントは、次の2つの情報によって決定されます.
  • メソッド(プログラム実行ポイント、すなわちどのターゲットメソッドにあるかを示す)
  • 相対点(方位、すなわちターゲットメソッドのどこを表すか、例えば呼び出し前、後など) 簡単に言えば、接続点はブロックされたプログラム実行点であり、Springはメソッドタイプの接続点のみをサポートするため、Springでは接続点がブロックされたメソッドである.
  • @Before("pointcut()")
    public void log(JoinPoint joinPoint) { //  JoinPoint       
    }
    

    (4)接点(PointCut)
    切り込みポイントは、接続ポイントをブロックする条件定義です.切り込み点式が接続点とどのように一致するかはAOPの核心であり、SpringではデフォルトでAspectJ切り込み点構文が使用されます.すべての方法は接続点と考えられるが,すべての方法に通知を追加することは望ましくないが,アクセスポイントの役割は,接続点に一致し,ルールを満たす接続点に通知を追加するためのルールのセットを提供することである.
    @Pointcut("execution(* com.remcarpediem.test.aop.service..*(..))")
    public void pointcut() {
    }
    

    上の切り込み点のマッチングルールはcomである.remcarpediem.test.aop.サービスパッケージの下にあるすべてのクラスのすべての関数.実は@Pointcutは単独で書くことができなくて、接続点の中で合併することができて、簡潔に書きます
    @Before("execution(* com.remcarpediem.test.aop.service..*(..))")
    public void log(JoinPoint joinPoint) { //  JoinPoint       
    }
    

    (5)通知(Advice)
    通知とは、接続ポイントをブロックした後に実行するコードで、「around」、「before」、「after」などの異なるタイプの通知が含まれています.Spring AOPフレームワークは、ブロッキングによって通知モデルを実装し、接続点を中心としたブロッキングチェーンを維持します.
    // @Before          ,log            ,JoinPoint    ,
    @Before("pointcut()")
    public void log(JoinPoint joinPoint) { 
    }
    

    (6)織り込み(Weaving)
    織り込みは、フェースとビジネスロジックオブジェクトを接続し、通知エージェントを作成するプロセスです.織り込みは、コンパイル時、クラスロード時、および実行時に完了できます.コンパイル時に織り込むのが静的エージェントであり,実行時に織り込むのが動的エージェントである.
    (7)エンハンサー(Adviser)
    Advisorは、ターゲットオブジェクトに通知をより複雑に織り込むことができ、通知をより複雑な切断面にパッケージするアセンブリである.Advisorは、切り込みポイントとAdviceで構成されています.Advisorという概念はSpringのAOPに対する支持から来ており,AspectJには等価な概念はない.Advisorは小さな自己含むうどんのようで、このうどんには通知が1つしかありません.フェース自体はBeanで表され、デフォルトのインタフェースを実装する必要があります.
    // AbstractPointcutAdvisor     
    public class LogAdvisor extends AbstractPointcutAdvisor {
        private Advice advice; // Advice
        private Pointcut pointcut; //    
    
        @PostConstruct
        public void init() {
            // AnnotationMatchingPointcut                    。
            this.pointcut = new AnnotationMatchingPointcut((Class) null, Log.class);
            //   
            this.advice = new LogMethodInterceptor();
        }
    }
    

    深く理解する
    上の理論の部分の知識を見終わって、私はやはり多くの友达がAOPの概念がまだはっきりしていないと感じていると信じて、AOPの用語に対して理解するのはまだ十分ではありません.今、具体的なケースを探して説明します. 簡単に言えば、aspect全体はpointcutルールを満たすjoinpointが対応するadvice操作を追加すると記述することができる.次の例を見てみましょう.
    @Component
    @Aspect //   
    public class LogAspect {
        private final static Logger LOGGER = LoggerFactory.getLogger(LogAspect.class.getName());
         //    ,     com.remcarpediem.test.aop.service
         //            
        @Pointcut("execution(* com.remcarpediem.test.aop.service..*(..))")
        public void aspect() {}
        //   ,   aspect             ,            
        @Before("aspect()")
        public void log(JoinPoint joinPoint) { //         
            if (LOGGER.isInfoEnabled()) {
                //     ,   ,       。
                Signature signature = joinPoint.getSignature();
                String className = joinPoint.getTarget().getClass().getName();
                String methodName = joinPoint.getSignature().getName();
                Object[] arguments = joinPoint.getArgs();
                MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
    
                String[] argumentNames = methodSignature.getParameterNames();
    
                StringBuilder sb = new StringBuilder(className + "." + methodName + "(");
    
                for (int i = 0; i< arguments.length; i++) {
                    Object argument = arguments[i];
                    sb.append(argumentNames[i] + "->");
                    sb.append(argument != null ? argument.toString() : "null ");
                }
                sb.append(")");
    
                LOGGER.info(sb.toString());
            }
        }
    }
    

    上のコードは簡単なログ関連の断面で、切り込み点と通知を順番に定義していますが、接続点はlogのパラメータとして入ってきて、接続点関数の名前、パラメータなどを取得するなど、一定の操作を行います.
    静的プロキシモード
    静的エージェントとは,AOPフレームワークがコンパイル段階でAOPエージェントクラスを生成するため,コンパイル時のエンハンスメントとも呼ばれる.ApsectJは静的エージェントの実装の一つであり,最も流行している.静的エージェントはコンパイル時にエージェントクラスを生成するため,動的エージェントよりも効率が高い.AspectJは単独でもSpringと組み合わせても使用できます.
    ダイナミックプロキシモード
    静的エージェントとは異なり,動的エージェントとは,AOPフレームワークがコンパイル時に生成したバイトコードを修正することなく,実行時にメモリにAOPエージェントオブジェクトを生成することであり,このAOPオブジェクトにはターゲットオブジェクトのすべてのメソッドが含まれ,特定の接点で拡張処理を行い,元のオブジェクトのメソッドをコールバックする.
    Spring AOPにおける動的エージェントには主に2つの方式がある:JDK動的エージェントとCGLIB動的エージェント.
  • JDKエージェントは、反射によって被エージェントのクラスを処理し、被エージェントクラスにインタフェースを実装する必要がある.コアクラスはInvocationHandlerインタフェースとProxyクラスです.ターゲットクラスがインタフェースを実装していない場合、Spring AOPフレームワークはCGLIBを使用してターゲットクラスを動的にエージェントします.
  • CGLIB(コードジェネレーションLibrary)は、あるクラスのサブクラスを実行時に動的に生成できるコード生成クラスライブラリです.CGLIBは継承方式で動的エージェントを行うため、クラスにfinalとマークされている場合、CGLIBを動的エージェントとして使用することはできません.コアクラスはMethodInterceptorインタフェースとEnhancerクラス
  • です.
    最後に、AOPの基本概念をまとめ、Spring AOP 基本概念_第3张图片を記憶するのに役立ちます.