Spring Frameworkチュートリアル(4):AOPアスペクト指向プログラミング

1つ、AOPの概要

1.AOPとは

  • AOPの変換はアスペクト指向プログラミングです。AOPを使用すると、ビジネスロジックのさまざまな部分を分離できるため、ビジネスロジックのさまざまな部分間の結合が減少し、プログラムの再利用性が向上し、開発が行われます。効率が向上します。
  • 素人の言葉で言えば、ソースコードを変更するのではなく、新しい関数をモジュールに分離するために、新しい関数をメイン関数に追加する必要があります。

2.基本原則(動的プロキシ)

  • 最初のタイプ:JDKの動的プロキシを使用するインターフェースがあります

  たとえば、次のように、UserDaoクラスインターフェイスとUserDaoImpl実装クラスがあります。

	interface UserDao{
    
    
		void login();
	}

	public class UserDaoImpl implements UserDao{
    
    
		public void login(){
    
    
			//登录实现过程
		}
	}

  JDK動的プロキシの動作原理は次のとおりです。UserDaoインターフェイス実装クラスのプロキシオブジェクトを作成し、プロキシオブジェクトを介してインターフェイスのメソッドを拡張します。

  • 2番目のタイプ:インターフェイスなし、CGLIBの動的プロキシを使用

  たとえば、次のようなUserクラスがあります。

	class User{
    
    
		public void add(){
    
    
			...
		}
	}

  CGLIB動的プロキシの動作原理は次のとおりです。Userクラスのサブクラスのプロキシオブジェクトを作成し、プロキシオブジェクト介してインターフェイスメソッドを拡張します。

3.AOPの運用条件

  • 接続ポイント:クラス内のどのメソッドを拡張できるか、これらのメソッドは接続ポイントと呼ばれます。
  • エントリポイント:実際に拡張されるメソッド。
  • 通知(拡張):ログや権限の判断など、実際の拡張の論理部分。通知は、事前通知、事後通知、周辺通知、例外通知、および最終通知に分けられます。
  • アスペクト:エントリポイントに通知を適用するプロセス。

2、AOP操作-準備

  Springフレームワークは通常、AOP操作を実装するためにAspectJに基づいています。AspectJはSpringの一部ではありませんが、独立したAOPフレームワークです。通常、AspectJとSpringフレームワークは、AOP操作を実行するために一緒に使用されます。

  AspectJに基づくAOP操作:xml構成ファイルに基づいて、注釈に基づいて(一般的に使用されます)。

  • 依存関係のインポート:

  以前のjarパッケージに加えて、他のいくつかのjarパッケージも必要です。

  spring-aspects-5.2.6.RELEASE.jar(spring-framework-5.2.6.RELEASE文件夹中能找到)
  com.springsource.net.sf.cglib-2.2.0.jar
  com.springsource.org.aopalliance- 1.0.0.jar
  com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar

  • エントリポイントの式を理解します。

  実行([アクセス許可修飾子] [戻り値の型] [クラスフルパス] [メソッド名] [([パラメーターパス]))

  例1com.wang.dao.BookDaoのaddメソッドを拡張します:excution(* com.wang.dao.BookDao.add(...))、最初のアスタリスクはすべての権限を示し、戻り値の型とパラメーターリストは省略されています代わりに2つのドットを使用してください。

  例2com.wang.dao.BookDaoのすべてのメソッドを拡張します:excution(* com.wang.dao.BookDao。*)。

  例3com.wang.dao.BookDaoのすべてのクラスのすべてのメソッドを拡張します:excution(* com.wang.dao。*。*)。

3、AspectJアノテーション

1.基本的な手順

  依存関係をインポートしてspring5_demo1プロジェクトを開きます。

(1)クラスを作成し、クラス内のメソッドを定義します

  この章の内容を学習するためのいくつかのクラスを格納するために、com.wangパッケージの下に新しいaspectJパッケージを作成します。次のようにFamilyクラスを作成します。

	package com.wang.aspectJ;
	import org.springframework.stereotype.Component;
	
	@Component
	public class Family {
    
    
	    public void add(){
    
    
	        System.out.println("add...family...");
	    }
	}

(2)拡張クラスを作成する

  次のように、Familyクラスの拡張クラスFamilyProxyを作成します。

	package com.wang.aspectJ;
	
	import org.aspectj.lang.annotation.Aspect;
	import org.springframework.stereotype.Component;
	
	@Component
	@Aspect
	public class FamilyProxy {
    
    
	}

(3)通知を構成します

  • アノテーションスキャンをオンにします:xml構成ファイルを介して(コンテキスト、aop名前空間も構成する必要があります)、または構成クラスを直接使用します。xmlファイルはsrcの下に配置する必要がありますが、com.wangの下には配置しないでください。エラーが報告されます。
  • アノテーションを使用してFamilyオブジェクトとFamilyProxyオブジェクトを作成します。@ Componentを使用します。
  • 拡張クラスFamilyProxyにアノテーション@Aspectを追加します。
  • 次のように、Spring構成ファイルでプロキシオブジェクトの生成をオンにします。
	<!--开启Aspect生成代理对象
    将加了@Aspect注解的类生成代理对象-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

(4)さまざまなタイプの通知を構成する

  拡張クラスで、対応する通知メソッドに応答アノテーションを追加し、カットイン式を使用します。改善された拡張クラスは次のとおりです。

	package com.wang.aspectJ;
	import org.aspectj.lang.ProceedingJoinPoint;
	import org.aspectj.lang.annotation.*;
	import org.springframework.stereotype.Component;
	
	@Component
	@Aspect
	public class FamilyProxy {
    
    
	    //事前通知:执行顺序2
	    @Before(value = "execution(* com.wang.aspectJ.Family.add(..))")
	    public void before(){
    
    
	        System.out.println("事前通知...");
	    }
	
	    //环绕通知
	    @Around(value = "execution(* com.wang.aspectJ.Family.add(..))")
	    public void around(ProceedingJoinPoint p) throws Throwable{
    
    
	        System.out.println("环绕之前...");//执行顺序1
	        p.proceed(); //被增强的方法执行:执行顺序3
	        System.out.println("环绕之后...");//执行顺序4
	
	    }
	
	    //最终通知:执行顺序5,方法执行后执行
	    @After(value = "execution(* com.wang.aspectJ.Family.add(..))")
	    public void after(){
    
    
	        System.out.println("最终通知...");
	    }
	
	    //异常通知:发生异常时执行
	    @AfterThrowing(value = "execution(* com.wang.aspectJ.Family.add(..))")
	    public void afterThrowing(){
    
    
	        System.out.println("异常通知...");
	    }
	
	    //后置(返回)通知:执行顺序6,返回值之后执行,有异常时不执行
	    @AfterReturning(value = "execution(* com.wang.aspectJ.Family.add(..))")
	    public void afterReturning(){
    
    
	        System.out.println("后置通知...");
	    }
	}

(5)最後にテストします

	@Test
    public void testFamily(){
    
    
        ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
        Family family=context.getBean("family",Family.class);

        System.out.println(family);
        family.add();
    }

ここに画像の説明を挿入

2.パブリックエントリポイントの抽出

	package com.wang.aspectJ;
	import org.aspectj.lang.ProceedingJoinPoint;
	import org.aspectj.lang.annotation.*;
	import org.springframework.stereotype.Component;
	
	@Component
	@Aspect
	public class FamilyProxy {
    
    
	    //切入点抽取
	    @Pointcut(value="execution(* com.wang.aspectJ.Family.add(..))")
	    public void point(){
    
    }
	
	    //事前通知:执行顺序②
	    @Before(value = "point()")
	    public void before(){
    
    
	        System.out.println("事前通知...");
	    }
	
	    //环绕通知
	    @Around(value = "point()")
	    public void around(ProceedingJoinPoint p) throws Throwable{
    
    
	        System.out.println("环绕之前...");//执行顺序①
	        p.proceed(); //被增强的方法执行:执行顺序③
	        System.out.println("环绕之后...");//执行顺序④
	
	    }
	
	    //最终通知:执行顺序⑤,方法执行后执行
	    @After(value = "point()")
	    public void after(){
    
    
	        System.out.println("最终通知...");
	    }
	
	    //异常通知:发生异常时执行
	    @AfterThrowing(value = "point()")
	    public void afterThrowing(){
    
    
	        System.out.println("异常通知...");
	    }
	
	    //后置(返回)通知:执行顺序⑥,返回值之后执行,有异常时不执行
	    @AfterReturning(value = "point()")
	    public void afterReturning(){
    
    
	        System.out.println("后置通知...");
	    }
	}

3.複数の拡張クラスが同じメソッドを拡張し、拡張クラスの優先度を設定します

  拡張クラスの上にアノテーション@Order(数値型の値)を追加します。値が小さいほど、優先度が高くなります。

4、AspectJ構成ファイル

1.クラスを作成して強化する

  次のように、aspectJパッケージにCityクラスとCityProxyクラスを作成します。

	package com.wang.aspectJ;
	
	public class City {
    
    
	    public void add(){
    
    
	        System.out.println("city add...");
	    }
	}
	
	public class CityProxy {
    
    
	    public void before(){
    
    
	        System.out.println("before...");
	    }
	}

2.Spring構成ファイルに2つのクラスオブジェクトを作成します

  以前のコンテンツから分離するために、新しいxml構成ファイルを作成しました。

  • 名前空間aopを導入します。
  • 2つのクラスのオブジェクトを作成します。
	<!--创建City类和CityProxy类的对象-->
    <bean id="city" class="com.wang.aspectJ.City"></bean>
    <bean id="cityProxy" class="com.wang.aspectJ.CityProxy"></bean>

3.Spring構成ファイルでエントリポイントを構成します

	<!--配置aop增强-->
    <aop:config>
        <!--切入点-->
        <aop:pointcut id="p1" expression="execution(* com.wang.aspectJ.City.add(..))"/>
        <!--切面-->
        <aop:aspect ref="cityProxy">
            <!--具体的增强-->
            <aop:before method="before" pointcut-ref="p1"/>
        </aop:aspect>
    </aop:config>

4.テスト

  テストメソッドを自分で記述します。実行結果は次のとおりです。

ここに画像の説明を挿入

5つの純粋なアノテーション開発

  AOP構成クラスの記述方法は次のとおりです。

	package com.wang.config;
	
	import org.springframework.context.annotation.ComponentScan;
	import org.springframework.context.annotation.Configuration;
	import org.springframework.context.annotation.EnableAspectJAutoProxy;
	
	@Configuration
	@ComponentScan(basePackages = {
    
    "com.wang"}) //开启注解扫描
	@EnableAspectJAutoProxy(proxyTargetClass = true) //开启@Aspect生成代理对象
	public class ConfigAop {
    
    
	}

おすすめ

転載: blog.csdn.net/Tracycoder/article/details/112654288