春の学習の要約(9):AspectJでAOPを開発する2つの方法

1.XMLベースの宣言型

       XMLベースの宣言型とは、Spring構成ファイルを介してアスペクト、ポイントカット、および宣言通知を定義することを意味し、すべてのアスペクトと通知は<aop:config>要素で定義する必要があります。

       次のように実行します。

       (1)jarパッケージをインポートします。

   <!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>5.2.6.RELEASE</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/aopalliance/aopalliance -->
    <dependency>
      <groupId>aopalliance</groupId>
      <artifactId>aopalliance</artifactId>
      <version>1.0</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.8.13</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjrt -->
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjrt</artifactId>
      <version>1.8.9</version>
    </dependency>

       (2)Bookクラスを作成します

public class Book {
    public void addBook(){
        System.out.println("add Book……");
    }
    public void updateBook(){
        System.out.println("update Book……");
    }

}

       (3)BookProxyクラスを作成します

public class BookProxy {
    public void before(){
        System.out.println("before……");
    }
    public void after(){
        System.out.println("after……");
    }
    public void afterReturing(){
        System.out.println("afterReturing……");
    }
    public void afterThrowing(){
        System.out.println("afterThrowing……");
    }
    public void around(ProceedingJoinPoint point) throws Throwable {
        System.out.println("around  之前……");
        point.proceed();
        System.out.println("around  之后……");
    }
}

       (4)bean.xmlのBean構成とaop構成。

    <!--  基于XML的AOP实现  -->
    <!--  配置bean  -->
    <bean id="book" class="com.yht.example6.Book"></bean>
    <bean id="bookProxy" class="com.yht.example6.BookProxy"></bean>
    <!-- aop配置   -->
    <aop:config>
        <!--
            expression : 配置切入点的具体位置
            id:切入点的id
         -->
        <aop:pointcut id="p1" expression="execution(* com.yht.example6.Book.*(..))"/>
        <!--    -->
        <aop:aspect ref="bookProxy">
            <aop:before method="before" pointcut-ref="p1"></aop:before>
            <aop:after method="after" pointcut-ref="p1"></aop:after>
            <aop:after-returning method="afterReturing" pointcut-ref="p1"></aop:after-returning>
            <aop:after-throwing method="afterThrowing" pointcut-ref="p1"></aop:after-throwing>
            <aop:around method="around" pointcut-ref="p1"></aop:around>
        </aop:aspect>
    </aop:config>

       (5)ユニットテストを実行します

    @Test
    public void testBook(){
        ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
        Book book = context.getBean("book", Book.class);
        book.addBook();
    }

       実行結果は以下のとおりです。

 

2つの注釈ベースの宣言型

       Springでは、XML構成ファイルを使用することでAOP開発を実現できますが、関連するすべての構成が構成ファイルに集中していると、必然的にXML構成ファイルが肥大化し、保守やアップグレードに一定の困難が生じます。AspectJフレームワークは、AOP開発のための別の開発方法であるアノテーションに基づく宣言型を提供します。AspectJでは、アノテーションを使用してアスペクト、ポイントカット、および拡張機能を定義できますが、Springフレームワークでは、これらのアノテーションに基づいてAOPプロキシを識別および生成できます。一般的な注釈は次のように導入されています。

名前 説明
@側面 アスペクトを定義するために使用されます
@前 BeforeAdviceと同等の事前通知を定義するために使用されます
@AfterReturning AfterReturningAdviceと同等の投稿通知を定義するために使用されます
@Around MethodInterceptorと同等のサラウンド通知を定義するために使用されます
@AfterThrowing ThrowAdviceと同等の例外スロー通知を定義するために使用されます
@After 最終(最終)通知を定義するために使用され、異常であるかどうかに関係なく、通知が実行されます
@DeclareParents IntroductionInterceptor(理解)と同等の紹介通知を定義するために使用されます

       (1)bean.xmlで構成します。

<!--  配置注解扫描的包  -->
    <context:component-scan base-package="com.yht.example6"></context:component-scan>
    <!--   
        通过aop命名空间的<aop:aspectj-autoproxy />声明自动为spring容器中那些配置@aspectJ切面的bean创建代理,织入切面。
     -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

       aop名前空間の<aop:aspectj-autoproxy />宣言により、Springコンテナの@aspectJアスペクトで設定されたBeanのプロキシが自動的に作成され、アスペクトが織り込まれます。<aop:aspectj-autoproxy />にはproxy-target-class属性があり、これはデフォルトでfalseです。proxy-target-classの属性値がfalseに設定されているか、この属性が省略されている場合、標準のJDKインターフェースベースのプロキシが有効になります。<aop:aspectj-autoproxy poxy-target-class = "true" />として構成されている場合、それはCGLib動的プロキシテクノロジーを使用して織り込み、拡張することを意味します。ただし、proxy-target-classがfalseに設定されている場合でも、ターゲットクラスがインターフェイスを宣言していない場合、springは自動的にCGLib動的プロキシを使用します。

       (2)Userクラスを作成します

@Component
public class User {
    public void addUser(){
        System.out.println("添加用户");
    }
    public void updateUser(){
        System.out.println("修改用户");
    }
    public void deleteUser(){
        System.out.println("删除用户");
    }
    public void searchUser(){
        System.out.println("查找用户");
    }

}

       (3)UserProxyを作成します

@Component
@Aspect
public class UserProxy {
    @Before(value = "execution(* com.yht.example6.User.addUser(..))")
    public void before(){
        System.out.println("方法执行之前");
    }
    @After(value = "execution(* com.yht.example6.User.addUser(..))")
    public void after(){
        System.out.println("方法执行之后");
    }
    @AfterReturning(value = "execution(* com.yht.example6.User.addUser(..))")
    public void afterReturning(){
        System.out.println("返回后通知");
    }
    @AfterThrowing(value = "execution(* com.yht.example6.User.addUser(..))")
    public void afterThrowing(){
        System.out.println("抛出异常后通知");
    }
    @Around(value = "execution(* com.yht.example6.User.addUser(..))")
    public void around(ProceedingJoinPoint point) throws Throwable {
        System.out.println("环绕通知——方法执行之前");
        point.proceed();
        System.out.println("环绕通知——方法执行之后");
    }
}

       (4)ユニットテストを実行します。

    @Test
    public void testUser(){
        ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
        User user = context.getBean("user", User.class);
        user.addUser();
    }

       実行結果は以下のとおりです。

いくつかの注意:

       (1)プログラムが異常な場合にafterThrowingメソッドを実行し、ユーザーのaddUser()がプログラムを異常なものにします。メソッドが実行されるかどうかを確認します。

    @AfterThrowing(value = "execution(* com.yht.example6.User.addUser(..))")
    public void afterThrowing(){
        System.out.println("抛出异常后通知");
    }

       NumberFormatExceptionを作成します。

    public void addUser(){
        int val = Integer.parseInt("123ab");//异常
        System.out.println("添加用户");
    }

        結果は次のとおりです。

(2)@Orderの紹介

       @Orderアノテーションは、コンポーネントの順序を宣言するために使用されます。値が小さいほど、優先度が高くなり、実行/初期化が早くなります。そのような注釈がない場合、優先度は最低です。上記のコードでは、@ Order(1)を指定して別のPersonProxyクラスを追加し、@ Order(5)を指定してUserProxyを追加すると、実行結果は、PersonProxyのbeforeメソッドがUserProxyのbeforeメソッドの前に実行されることになります。

       1)PersonProxyクラスを定義します。

@Component
@Aspect
@Order(1)
public class PersonProxy {
    @Before(value = "execution(* com.yht.example6.User.addUser(..))")
    public void beforeMethod(){
        System.out.println("我是PersonProxy的before方法");
    }
}

       2)@Order(5)をUserProxyに追加します。

       3)テストを実行します。結果は次のとおりです。

       (3)同じエントリポイントの抽出

       上記の例では、UserProxyの5つの通知構成に同じエントリポイント式があり、それらを抽出して、各通知の注釈で引用することができます。したがって、UserProxyクラスは次のようになります。

@Component
@Aspect
@Order(5)
public class UserProxy {
    
    @Pointcut(value = "execution(* com.yht.example6.User.addUser(..))")
    public void commonMsg(){}
    
    @Before(value = "commonMsg()")
    public void before(){
        System.out.println("方法执行之前");
    }
    @After(value = "commonMsg()")
    public void after(){
        System.out.println("方法执行之后");
    }
    @AfterReturning(value = "commonMsg()")
    public void afterReturning(){
        System.out.println("返回后通知");
    }
    @AfterThrowing(value = "commonMsg()")
    public void afterThrowing(){
        System.out.println("抛出异常后通知");
    }
    @Around(value = "commonMsg()")
    public void around(ProceedingJoinPoint point) throws Throwable {
        System.out.println("环绕通知——方法执行之前");
        point.proceed();
        System.out.println("环绕通知——方法执行之后");
    }
}

       最終結果は以前と同じになります。

       (4)AOP純粋な注釈の開発 

       AOPの純粋なアノテーション開発は基本的にIOCアノテーション開発に似ており、構成クラスを提供します。コメントを追加:

@Configuration
@ComponentScan(basePackages = "com.yht.example6")
//@EnableAspectJAutoProxy标记在主配置类上,表示开启基于注解的aop模式
@EnableAspectJAutoProxy
public class AopConfig {
}

テストは次のとおりです。

    @Test
    public void testUserAnno(){
        ApplicationContext context = new AnnotationConfigApplicationContext(AopConfig.class);
        User user = context.getBean("user", User.class);
        user.addUser();
    }

 

おすすめ

転載: blog.csdn.net/weixin_47382783/article/details/112821681