Springの高度なソースコードノート:Springでの3つのAOP構成メソッドのコード実装と詳細な分析!

1.SpringでのAOPの構成

SpringのAOP構成では、IoC構成と同様に、3種類の構成方法がサポートされています。

最初のカテゴリ:XML構成を使用する

2番目のカテゴリ:XML +注釈の組み合わせ構成を使用する

3番目のカテゴリ:純粋な注釈構成を使用する

Springでの2、3構成のAOPメソッドコードの実装

要件:横断的なロジックコードはログを印刷することであり、印刷ログのロジックをターゲットメソッド(サービスレイヤー転送メソッド)の特定の場所に織り込むことを望んでいます。



この記事は、アシスタントVXを追加する必要がある学生である「SpringAdvancedSourceNotes」に言及しています。C18173184271,备注一下从哪个平台加我的工作几年了!無料で入手してください。

1.XMLスキーマ

Springこれはモジュラー開発のフレームワークであり、aopを使用してaopjarを導入します

  • 座標
<dependency>
 	<groupId>org.springframework</groupId>
 	<artifactId>spring-aop</artifactId>
 	<version>5.1.12.RELEASE</version>
</dependency> 
<dependency>
 	<groupId>org.aspectj</groupId>
 	<artifactId>aspectjweaver</artifactId>
 	<version>1.9.4</version>
</dependency>
  • AOPコア構成
<!--
 Spring基于XML的AOP配置前期准备:在spring的配置文件中加入aop的约束
 xmlns:aop="http://www.springframework.org/schema/aop" http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd 
 
 Spring基于XML的AOP配置步骤:
 	第一步:把通知Bean交给Spring管理
 	第二步:使用aop:config开始aop的配置
 	第三步:使用aop:aspect配置切面
 	第四步:使用对应的标签配置通知的类型
 		入门案例采用前置通知,标签为aop:before
-->
<!--把通知bean交给spring来管理-->
<bean id="logUtil" class="com.lagou.utils.LogUtil"></bean>

<!--开始aop的配置-->
<aop:config>
<!--配置切⾯-->
 	<aop:aspect id="logAdvice" ref="logUtil">
<!--配置前置通知-->
 	<aop:before method="printLog" pointcut="execution(public *
com.lagou.service.impl.TransferServiceImpl.updateAccountByCardNo(com.lagou
.pojo.Account))"></aop:before>
 	</aop:aspect>
</aop:config>
  • 詳細

    • 上記のポイントカット式については、実装前に拡張TransferServiceImplするupdateAccountByCardNo方法、ロギングステートメントの出力が可能です。ここで、私たちは比較的なじみのない名前に出くわしました:ポイントカット式、それは何をしますか?見下ろしてみましょう。
    • 概念と機能ポイントカット式はAspectJポイントカット
      式とも呼ばれ、特定の文法構造に従う文字列指しますその役割は、文法形式に準拠する接続ポイントを拡張することですこれはAspectJ式の一部です。
    • AspectJについてAspectJ
      はJava言語に基づくAOPフレームワークです。バージョン2.0以降、SpringフレームワークはAspectJフレームワークのポイントカット式部分を統合し、AspectJポイントカット式のサポートを開始しました。
    • ポイントカット式の使用例
全限定法名 	  访问修饰符 	  返回值 	  包名.包名.包名.类名.方法名(参数列表)
 			全匹配方式:
		public void
com.lagou.service.impl.TransferServiceImpl.updateAccountByCardNo(c
om.lagou.pojo.Account)
 访问修饰符可以省略
 		void
com.lagou.service.impl.TransferServiceImpl.updateAccountByCardNo(c
om.lagou.pojo.Account)
 返回值可以使用*,表示任意返回值
 *
com.lagou.service.impl.TransferServiceImpl.updateAccountByCardNo(c
om.lagou.pojo.Account)
包名可以使用.表示任意包,但是有几级包,必须写几个
 *
....TransferServiceImpl.updateAccountByCardNo(com.lagou.pojo.Accou
nt)
 包名可以使用..表示当前包及其子包
 *
..TransferServiceImpl.updateAccountByCardNo(com.lagou.pojo.Account
)
 		类名和方法名,都可以使用.表示任意类,任意方法
 		* ...(com.lagou.pojo.Account)
 		参数列表,可以使用具体类型
 		基本类型直接写类型名称 : int
 		引用类型必须写全限定类名:java.lang.String
 		参数列表可以使用*,表示任意参数类型,但是必须有参数
 		* *..*.*(*)
 		参数列表可以使用..,表示有无参数均可。有参数可以是任意类型
		 * *..*.*(..)
 		全通配方式:
 		* *..*.*(..)
  • プロキシモードの構成の変更前述したように、
    Springがプロキシオブジェクトの作成を選択すると、プロキシオブジェクトの実際の状況に応じて選択されます。プロキシオブジェクトがインターフェイスを実装している場合、インターフェイスに基づく動的プロキシが使用されます。プロキシオブジェクトがインターフェイスを実装していない場合、Springはサブクラスに基づいて動的プロキシモードに自動的に切り替わります。
    しかし、プロキシオブジェクトがインターフェイスを実装しているかどうかに関係なく、最終的に変更されたクラスでない限り、cglibが提供する方法でプロキシオブジェクトを作成できることは誰もが知っています。したがって、Springもこの状況を考慮し、サブクラスベースの動的プロキシの使用を強制するための構成メソッド(つまり、cglibメソッド)を提供します。構成には2つの方法があります。
  • aop:configラベル構成を使用する
<aop:config proxy-target-class="true">
  • aop:aspectj-autoproxyラベル構成を使用する
<!--此标签是基于XML和注解组合配置AOP时的必备标签,表示Spring开启注解配置AOP的支持-->
<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectjautoproxy>
  • 5つの通知タイプ
    • 事前通知
      設定方法:aop:beforeラベル
<!--
 作用:
	 用于配置前置通知。
 出现位置:
 	它只能出现在aop:aspect标签内部
 属性:
 	method:用于指定前置通知的方法名称
 	pointcut:用于指定切入点表达式
 	pointcut-ref:用于指定切入点表达式的引用
-->
<aop:before method="printLog" pointcut-ref="pointcut1">
</aop:before>

実行のタイミング

事前通知は、常にポイントカット方式(ビジネスコア方式)が実行される前に実行されます。

詳細

事前通知により、ポイントカット方式のパラメータを取得して拡張することができます。

  • 通常実行時の通知
    設定方法
<!--
 作用:
 	用于配置正常执行时通知
 出现位置:
 	它只能出现在aop:aspect标签内部
 属性:
	 method:用于指定后置通知的方法名称
 	 pointcut:用于指定切入点表达式
	 pointcut-ref:用于指定切入点表达式的引用
 -->
<aop:after-returning method="afterReturningPrintLog" pointcutref="pt1"></aop:after-returning>
  • 例外通知

構成方法

<!--
 作用:
 	用于配置异常通知。
 出现位置:
 	它只能出现在aop:aspect标签内部
 属性:
	 method:用于指定异常通知的方法名称
 	 pointcut:用于指定切入点表达式
	 pointcut-ref:用于指定切入点表达式的引用
 
 -->
<aop:after-throwing method="afterThrowingPrintLog" pointcut-ref="pt1"
></aop:after-throwing>

実行のタイミング

例外通知の実行タイミングは、エントリポイント方式(ビジネスコア方式)の実行により例外が発生した後、例外通知が実行されます。ポイントカット方式を実行しても例外が発生しない場合、例外通知は実行されません。

詳細

例外通知は、ポイントカットメソッド実行のパラメータを取得できるだけでなく、ポイントカットメソッド実行によって生成された例外情報も取得できます。

  • 最終通知
    構成
<!--
 作用:
 	用于配置最终通知。
 出现位置:
 	它只能出现在aop:aspect标签内部
 属性:
	 method:用于指定最终通知的方法名称
 	 pointcut:用于指定切入点表达式
	 pointcut-ref:用于指定切入点表达式的引用
-->
<aop:after method="afterPrintLog" pointcut-ref="pt1"></aop:after>

実行のタイミング

最終通知の実行タイミングは、ポイントカット方式(ビジネスコア方式)を実行した後、ポイントカット方式が戻る前に実行されます。つまり、ポイントカットメソッドの実行で例外が発生するかどうかに関係なく、戻る前に実行されます。

詳細

最終通知を実行すると、通知方法のパラメータを取得できます。同時に、いくつかのクリーニング操作を実行できます。

  • サラウンド通知
    構成
<!--
 作用:
 	用于配置环绕通知。
 出现位置:
 	它只能出现在aop:aspect标签内部
 属性:
	 method:用于指定环绕通知的方法名称
 	 pointcut:用于指定切入点表达式
	 pointcut-ref:用于指定切入点表达式的引用
 
 -->
<aop:around method="aroundPrintLog" pointcut-ref="pt1"></aop:around>

2. XML +注釈モード

  • XMLでの注釈AOPに対するSpringのサポートを開く
<!--开启spring对注解aop的支持-->
<aop:aspectj-autoproxy/>
/**
* 模拟记录日志
* @author 应癫
*/

@Component
@Aspect
public class LogUtil {
    
    

 /**
 * 我们在xml中已经使用了通用切入点表达式,供多个切面使用,那么在注解中如何使用呢?
 * 第一步:编写一个方法
 * 第二步:在方法使用@Pointcut注解
 * 第三步:给注解的value属性提供切入点表达式
 * 细节:
 * 1.在引用切入点表达式时,必须是方法名+(),例如"pointcut()"。
 * 2.在当前切面中使用,可以直接写方法名。在其他切面中使用必须是全限定方法名。
 */
 @Pointcut("execution(* com.lagou.service.impl.*.*(..))")
 public void pointcut(){
    
    }
 
 @Before("pointcut()")
 public void beforePrintLog(JoinPoint jp){
    
    
 	Object[] args = jp.getArgs();
 	System.out.println("前置通知:beforePrintLog,参数是:"+ Arrays.toString(args));
 }
 
 @AfterReturning(value = "pointcut()",returning = "rtValue")
 public void afterReturningPrintLog(Object rtValue){
    
    
 	System.out.println("后置通知:afterReturningPrintLog,返回值是:"+rtValue);
 }
 
 @AfterThrowing(value = "pointcut()",throwing = "e")
 public void afterThrowingPrintLog(Throwable e){
    
    
 	System.out.println("异常通知:afterThrowingPrintLog,异常是:"+e);
 }
 
 @After("pointcut()")
 public void afterPrintLog(){
    
    
 	System.out.println("最终通知:afterPrintLog");
 }
 
 /**
 * 环绕通知
 * @param pjp
 * @return
 */
 
 @Around("pointcut()")
 public Object aroundPrintLog(ProceedingJoinPoint pjp){
    
    
 	//定义返回值
 	Object rtValue = null;
 	try{
    
    
 	
 		//前置通知
 		System.out.println("前置通知");
 		
 		//1.获取参数
 		Object[] args = pjp.getArgs();
 		
 		//2.执⾏切⼊点⽅法
 		rtValue = pjp.proceed(args);
 		
 		//后置通知
 		System.out.println("后置通知");
 	}catch (Throwable t){
    
    
 		//异常通知
 		System.out.println("异常通知");
 		t.printStackTrace();
 	}finally {
    
    
 		//最终通知
 		System.out.println("最终通知");
 		}
 	return rtValue;
	}
}

3.注釈モード

aopのアノテーション駆動型開発を使用する場合、アノテーションが構成ファイル内の次の構成行を置き換えることを明確にする必要があります。

<!--开启spring对注解aop的支持-->
<aop:aspectj-autoproxy/>

上記の構成を置き換えるには、構成クラスで次のアノテーションを使用します

/**
* @author 应癫
*/
@Configuration
@ComponentScan("com.lagou")
@EnableAspectJAutoProxy //开启spring对注解AOP的支持
public class SpringConfiguration {
    
    
}

このフルバージョンが必要な場合は《Spring高级源码笔记》、この記事で私をサポートするだけで済みます。

多くのサポート、あなたは無料で情報を得ることができます-3年連続で(約束:100%無料)

クイックスタートチャンネル:アシスタントVXを追加:C18173184271,备注一下从哪个平台加我的工作几年了!無料で入手!誠意あふれる!

春のインタビュー特集記事はこちら!

おすすめ

転載: blog.csdn.net/Java_Caiyo/article/details/113096250