[Spring aop]接続ポイント(ジョイントポイント)、エントリポイント(ポイントカット)、拡張(アドバイス)、アスペクト/アスペクト(アスペクト、アドバイザー)

序文

前章「静的プロキシモードとJDK、CGLIB動的プロキシ」では、静的プロキシとJDK、CGLIB動的プロキシを分析しました。次に、AOPのソースコードの次の分析を容易にするために、AOPに関するいくつかの関連知識を確認します。

1.最初にAOPのいくつかの用語を確認しましょう

  • 接続点(Jointpoint)は:プログラムの問題に拡張ポイントを断面を挿入する必要があり、発現の接続点は、実行、メソッド呼び出し、フィールド・コールまたはハンドル例外のクラスの初期化方法であってもよいなどスプリング支持体のみを接続ポイントとしてのメソッド実行。AOPでは「どこで実行するか」と表現されます。

    これはエントリポイントとして許可されるリソースであり、すべてのクラスのすべてのメソッドを接続ポイントとして使用できます。

  • ポイントカット:接続ポイントのコレクションと見なすことができる関連する接続ポイントパターンのセットを選択します。Springはperl5正規表現とAspectJポイントカットパターンをサポートします。SpringはデフォルトでAspectJ構文を使用します。これはAOPで「Wheredoyoudo」として表されます。それ? "コレクション";

    1つまたは複数の接続ポイントを選択することです。たとえば、クラスAにはrequest()とrequest2()の2つのメソッドがあります。クラスAのrequest()が呼び出されるすべての場所は、次のように選択できます。カットポイント。

  • 拡張(アドバイス):多くの場所で通知として理解されますが、より正確には拡張として理解されます。拡張とは、接続ポイントで実行される動作を意味します。拡張とは、選択した接続ポイントで既存の動作を拡張する必要があることを意味します。 AOP手段のエントリポイントによって;事前拡張(アドバイス前)、後拡張(アドバイス後)、サラウンド拡張(アドバイス周辺)を含む、春にプロキシモードを介してAOPを達成し、インターセプターモードを介してインターセプターチェーンウィービングの接続ポイント着信拡張。AOPでは「何をすべきか」と表現されます。

    2つの概念が含まれます。1つはタイミングを選択すること、フロント、バック、またはサラウンドを選択することです。もう1つは何をするかです。例としてフロントを取り上げます。beforeメソッドでは、ユーザー拡張ロジックが実装されます。

  • アスペクト/アスペクト(アドバイザとも呼ばれます):上記のログコンポーネントなど、横断的関心事のモジュール化。これは、拡張、導入、およびエントリポイントの組み合わせと見なすことができます。Springでは、Schemaと@AspectJを編成と実現に使用できます。AOPでは、「どこでどのコレクション」と表現されます。

    完全なものであるのは、前の概念の組み合わせです。たとえば、クラスAのrequest()メソッドが呼び出される前に拡張操作を実行します。1つは必須であり、request()メソッドが欠落していて、どこで実行すればよいかわかりません。before()がないと、拡張操作をいつ実行するかわからず、何を拡張するかわかりません。 。


    Advisor = Advice + Pointcut

  • タイプ間宣言:導入拡張は特別な拡張です。ターゲットメソッドの周りに拡張を織り込む代わりに、ターゲットクラスの新しいメソッドまたは属性を作成します。したがって、導入拡張の接続ポイントはクラスレベルにあります。メソッドレベルでは、Springを使用すると、すべてのプロキシオブジェクト(ターゲットオブジェクト)に新しいインターフェイス(実装に対応する必要があります)を導入できます。これは、AOPでは「何をするか(何を導入するか)」として表されます。

  • ターゲットオブジェクト:横断的関心事に織り込む必要のあるオブジェクト。つまり、オブジェクトはエントリポイントによって選択されたオブジェクトであり、拡張する必要のあるオブジェクトであり、「拡張オブジェクト」とも呼ばれます。 ; Spring AOPはプロキシを使用するためパターンが実現されるため、このオブジェクトは常にプロキシオブジェクトであり、AOPでは「誰に」と表現されます。

  • AOPプロキシ(AOPプロキシ):AOPフレームワークは、プロキシモードで作成されたオブジェクトを使用して、接続ポイントに拡張機能(つまり、アプリケーションアスペクト)を挿入します。これにより、プロキシを介してターゲットオブジェクトにアスペクトが適用されます。Springでは、AOPプロキシはJDK動的プロキシまたはCGLIBプロキシで実装でき、アスペクトはインターセプターモデルを介して適用されます。

  • ウィービング:ウィービングは、アスペクトをターゲットオブジェクトに適用して、AOPプロキシオブジェクトを作成するプロセスです。ウィービングは、コンパイル、クラスのロード、および実行時に実行できます。

上記の概念は比較的抽象的で退屈であり、実際の開発でのアスペクトプログラミングの使用はごく一部しか占めていませんが、上記の概念を理解していない場合は、次のソースコード分析は何もないはずです。以下のいくつかの例を使用して、すべての人が上記の概念を理解し、ソースコード分析の準備ができるようにします。

2.拡張方法の概要

拡張を通知として理解する人もたくさんいますが、接続ポイントで実行される動作を表すため、拡張として理解する方が正確です。この動作はターゲットクラスでは使用できません。これにより、メソッドやその他のメソッドが追加されます。ターゲットクラス。一部の関数なので、通知よりも拡張の方が適切であることがわかります。もちろん、この記事の拡張が通知であることがわかっている限り、通知の概念に慣れている人がいるかどうかは関係ありません。

エンハンスメントの種類には、プレエンハンスメント、リアリターンエンハンスメント、異常エンハンスメント、サラウンドエンハンスメント、イントロダクションエンハンスメント、ポストファイナルエンハンスメントなどがあります。以下の例を見てみましょう。SpringAopをより深く理解するために、最初に@AspectJまたはスキーマ構成ファイルに基づいて方法を説明するのではなく、非常に基本的なことから始めます。結局のところ、AOPは実際の開発では、それは大きな割合を占めておらず、多くの人が深い理解を持っていないと思います。

次に、最初に、Adviceインターフェースに基づくコーディングで実装された拡張機能について説明します。

2.1MethodBeforeAdviceの事前拡張

ターゲットインターフェイスと実装クラス:

package com.lyc.cn.v2.day04.advisor;

public interface Animal {
    
    
    void sayHello(String name,int age);
    void sayException(String name,int age);
}
package com.lyc.cn.v2.day04.advisor;

public class Dog implements Animal {
    
    

    @Override
    public void sayHello(String name, int age) {
    
    
        System.out.println("==名字:" + name + " 年龄:" + age);
    }

    @Override
    public void sayException(String name, int age) {
    
    
        System.out.println("==名字:" + name + " 年龄:" + age);
        System.out.println("==抛出异常:" + 1 / 0);
    }
}

事前に拡張されたMethodBeforeAdvice:

package com.lyc.cn.v2.day04.advisor;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;

public class MyMethodBeforeAdvice implements MethodBeforeAdvice {
    
    
   
    public void before(Method method, Object[] args, Object target) throws Throwable {
    
    
        System.out.println("==前置增强");
        System.out.println("==方法名:" + method.getName());
        if (null != args && args.length > 0) {
    
    
            for (int i = 0; i < args.length; i++) {
    
    
                System.out.println("==第" + (i + 1) + "参数:" + args[i]);
            }
        }
        System.out.println("==目标类信息:" + target.toString());
    }
}

2.2AfterReturningAdviceポストエンハンスメント

package com.lyc.cn.v2.day04.advisor;
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;

/**
 * 后置增强
 * @author: LiYanChao
 * @create: 2018-11-01 22:09
 */
public class MyAfterReturningAdvice implements AfterReturningAdvice {
    
    
    /**
     * Callback after a given method successfully returned.
     * @param returnValue the value returned by the method, if any
     * @param method      method being invoked
     * @param args        arguments to the method
     * @param target      target of the method invocation. May be {@code null}.
     * @throws Throwable if this object wishes to abort the call.
     *                   Any exception thrown will be returned to the caller if it's
     *                   allowed by the method signature. Otherwise the exception
     *                   will be wrapped as a runtime exception.
     */
    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
    
    
        System.out.println("==后置增强");
        System.out.println("==方法名:" + method.getName());
        if (null != args && args.length > 0) {
    
    
            for (int i = 0; i < args.length; i++) {
    
    
                System.out.println("==第" + (i + 1) + "参数:" + args[i]);
            }
        }
        System.out.println("==目标类信息:" + target.toString());
    }
}

2.3ThrowsAdvice例外の機能強化

package com.lyc.cn.v2.day04.advisor;
import org.springframework.aop.ThrowsAdvice;
import java.lang.reflect.Method;

/**
 * @author: LiYanChao
 * @create: 2018-11-01 22:17
 */
public class MyThrowsAdvice implements ThrowsAdvice {
    
    

    /**
     * 异常增强
     */
    public void afterThrowing(Method method, Object[] args, Object target, Exception ex) {
    
    
        System.out.println("==异常增强");
        System.out.println("==方法名:" + method.getName());
        if (null != args && args.length > 0) {
    
    
            for (int i = 0; i < args.length; i++) {
    
    
                System.out.println("==第" + (i + 1) + "参数:" + args[i]);
            }
        }
        System.out.println("==目标类信息:" + target.toString());
        System.out.println("==异常信息:" + ex.toString());
    }
}

2.4MethodInterceptorサラウンドエンハンスメント

package com.lyc.cn.v2.day04.advisor;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

/**
 * 环绕增强
 * @author: LiYanChao
 * @create: 2018-11-01 22:29
 */
public class MyMethodInterceptor implements MethodInterceptor {
    
    

    /**
     * 环绕增强 这里的方法参数与之前的前置增强、后置增强明显不同,只有一个MethodInvocation类型的参数
     * Implement this method to perform extra treatments before and
     * after the invocation. Polite implementations would certainly
     * like to invoke {@link Joinpoint#proceed()}.
     * @param invocation the method invocation joinpoint
     * @return the result of the call to {@link Joinpoint#proceed()};
     * might be intercepted by the interceptor
     * @throws Throwable if the interceptors or the target object
     *                   throws an exception
     */
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
    
    
        System.out.println("==环绕增强开始");
        System.out.println("==方法名:" + invocation.getMethod().getName());
        Object[] args = invocation.getArguments();
        if (null != args && args.length > 0) {
    
    
            for (int i = 0; i < args.length; i++) {
    
    
                System.out.println("==第" + (i + 1) + "参数:" + args[i]);
            }
        }

        Object proceed = invocation.proceed();

        System.out.println("==环绕增强结束");
        return proceed;
    }
}

2.5実行結果

@Test
public void test5() {
    
    
    // 前置增强
    // 1、实例化bean和增强
    Animal dog = new Dog();
    MyMethodBeforeAdvice advice = new MyMethodBeforeAdvice();

    // 2、创建ProxyFactory并设置代理目标和增强
    ProxyFactory proxyFactory = new ProxyFactory();
    proxyFactory.setTarget(dog);
    proxyFactory.addAdvice(advice);

    // 3、生成代理实例
    Animal proxyDog = (Animal) proxyFactory.getProxy();
    proxyDog.sayHello("二哈", 3);
}


@Test
public void test6() {
    
    
    // 后置增强
    // 1、实例化bean和增强
    Animal dog = new Dog();
    MyAfterReturningAdvice advice = new MyAfterReturningAdvice();

    // 2、创建ProxyFactory并设置代理目标和增强
    ProxyFactory proxyFactory = new ProxyFactory();
    proxyFactory.setTarget(dog);
    proxyFactory.addAdvice(advice);

    // 3、生成代理实例
    Animal proxyDog = (Animal) proxyFactory.getProxy();
    proxyDog.sayHello("二哈", 3);

}

@Test
public void test7() {
    
    
    // 异常增强
    // 1、实例化bean和增强
    Animal dog = new Dog();
    MyThrowsAdvice advice = new MyThrowsAdvice();

    // 2、创建ProxyFactory并设置代理目标和增强
    ProxyFactory proxyFactory = new ProxyFactory();
    proxyFactory.setTarget(dog);
    proxyFactory.addAdvice(advice);

    // 3、生成代理实例
    Animal proxyDog = (Animal) proxyFactory.getProxy();
    proxyDog.sayException("二哈", 3);

}


@Test
public void test8() {
    
    
    // 环绕增强
    // 1、实例化bean和增强
    Animal dog = new Dog();
    MyMethodInterceptor advice = new MyMethodInterceptor();

    // 2、创建ProxyFactory并设置代理目标和增强
    ProxyFactory proxyFactory = new ProxyFactory();
    proxyFactory.setTarget(dog);
    proxyFactory.addAdvice(advice);

    // 3、生成代理实例
    Animal proxyDog = (Animal) proxyFactory.getProxy();
    proxyDog.sayHello("二哈", 3);

}

3.まとめ

上記では、プリエンハンスメント、ポストエンハンスメント、サラウンドエンハンスメント、異常エンハンスメントのエンコーディング実装を簡単に紹介しています。もちろん、上記の実装は設定ファイルを介して実装することもできます。

この記事で紹介する知識ポイントは比較的単純ですが、拡張の概念を理解することがAOPの基礎です。実際、この記事のさまざまな拡張方法は、エージェントファクトリであるため、前の記事で説明した動的プロキシを使用して実装できます。この記事で使用することでProxyFactory使用されているどのような内部であるCglibAopProxyJdkDynamicAopProxy、実際には、その本質はまだJDKまたはCGLIBダイナミックプロキシです。次の章では、CglibAopProxyまたはJdkDynamicAopProxyの実装の詳細について説明する。この記事の分析はここにあります。


参照:

「28-Aopナレッジポイントのレビューとアドバイスインターフェイスに基づく実装の強化」

おすすめ

転載: blog.csdn.net/m0_45406092/article/details/115243643