10-AOPを学習春

AOP

AOPについて

、アスペクト指向プログラミングであるAOP(アスペクト指向プログラミング)を、添加し、改善された(オブジェクト指向プログラミング、オブジェクト指向プログラミング)OOPと言うことができます。OOPは、共通セットの動作をシミュレートするために使用されるオブジェクトの階層構造を構築するなど、カプセル化、継承、ポリモーフィズム、概念として導入しました。しかし、OOPは、開発者が上下関係を定義するが、例えば、対数関数、定義された横方向の関係に適していないことを可能にします。ログコードはすべてのオブジェクト階層に横方向に、機能に対応する中核オブジェクトは、セキュリティ、例外処理、および連続のようなコードの他のタイプには関係が、透明そうではないが拡散する傾向があり、このスプレッド独立したコードは、再利用可能なモジュールを犠牲にし、コードの繰り返しの多くにつながったオブジェクト指向設計において、横(横断)を通して呼ばれます。

「反して「横」と呼ばれる技術を使用していますAOP技術、内部断面デカプセル化オブジェクト、および再利用可能な複数のモジュールの中にカプセル化された公共のクラスの動作に影響を与えるもの、そしてそれを命名アスペクト」、すなわちセクション。簡単に重複したコードには、いわゆる「カット」、単にビジネスを行うためのものは何もありませんが、それはビジネスロジックやカプセル化と呼ばれる共通モジュールの責任である、システムを削減し、モジュール間の結合度を低減し、かつ将来の操作性を容易にするために、および保守性。

使用ソフトウェアシステムは、2つの部分に分かれている技術、AOPを「クロスカット」:コアの懸念横断的関心事ビジネスプロセスの主な流れは関係のない部分は、横断的関心事であり、コアの懸念です。横断的関心事は、彼らはしばしば、多くのコアの懸念に発生し、かつ、そのような認証局、ログものなど、どこにでも本質的に同様であることを特徴。AOPは、様々な問題分離システム、コア及び横断的関心事を分離することです。

AOPの中核となる概念

  • 懸念クロスカット:メソッドがインターセプトに何であったかを、どのように傍受、横断的関心事と呼ばれるこれらの懸念に対処します。そのようなので、ロギング、セキュリティ、キャッシング、トランザクション、など...
  • セクション(ASPECT):クラスは、抽象オブジェクトの特徴である、横断的関心事の抽象的な部分です。懸念をクロスカットする特殊なオブジェクトがモジュール化されていると言うことができます。つまり、それはクラスがあります。
  • 接続点(JointPoint):春のみ接続点型方法をサポートするためのポイントは、それがポイントであり、傍受されたスプリングで傍受する接続を意味し、実際には、結合点は、フィールドまたはコンストラクタであってもよいです
  • エントリポイント(ポイントカット):傍受の接続点を定義します。彼が発生し、対応する情報を定義するローカル関節点の群、関節点またはロジックの組み合わせによって、またはワイルドカードによって、正規表現等共にを表します。
  • 通知(アドバイス):インターセプトを行うことが後に通知が5つの通知に囲ま前部、後部、異常終了、に分割され、接続ポイントコードを意味する、いわゆる通知をいいます。節が行われなければなりません。つまり、それはクラスメソッドです。
  • 聴衆(ターゲット):プロキシターゲットオブジェクト
  • アスペクトプロセスと一緒に他のオブジェクトとのアドバイスを作成:織りを(ウィービング)
  • プロキシオブジェクト(プロキシ):アプリケーションは、ターゲットオブジェクトへの通知後に作成されたオブジェクト。
  • (導入)を導入する:コードを変更しないという前提の下で、それが中に導入することができるの操作方法またはダイナミッククラスフィールドを追加

例えば、理解しやすいです

ダイヤグラム

AOP

通知(アドバイス)タイプ

  • 前:アドバイスする前に
    、実行メソッドの前に強化されたエントリポイントの実装
  • リア通知:アフター復帰
    通常の方法を実行した後にポイントカット増強の実施形態を、それが唯一の異常通知を行うことができます
  • 異常通知:アフタースロー
    例外を高めるポイントカットを行った後にメソッドの実行中に発生します
  • 最終的な注意:後に
    異常が実行されるエントリポイント法に関係なく発生するかどうかは、その背面に実行します
  • アドバイス周り:周り
    には、Springフレームワークは、通常の状況下では、手動でコードにコードの実装を強化するために何時間制御する方法を提供してくれている、アドバイスの周りに別々に使用されています。

春AOPのサポート

SpringのIoCコンテナ春AOPプロキシが生成、管理を担当し、その依存関係もIOCコンテナによって管理する責任があります

したがって、AOP剤は、この関係は、依存性注入IOCコンテナを提供することができる、ターゲット容器のような他のBeanインスタンスを直接使用することができます。春はエージェントのルールを作成します。

1、デフォルトでは動的プロキシAOPプロキシを作成するためにJavaを使用するプロキシことのいずれかのインターフェイスのインスタンスを作成することができますので、

図2に示すように、クラスがプロキシインタフェースエージェントを必要としない場合、スプリングCGLIBプロキシを使用するように切り替わり、またCGLIBを強制するために使用することができます

AOPプログラミングは実際には非常に単純なこと、AOPプログラミングを見ている、プログラマは三つの部分に参加する必要は:

1、一般的なビジネス・コンポーネントの定義

2、出発点の定義は、出発点は、ビジネス・コンポーネントの複数の交差してもよいです

3、定義強調処理は、演算処理における強調処理は、コンポーネントが通常のトラフィックに織り込まれているフレームであるAOP

キーは、エントリポイントと定義AOP強調処理プログラムを定義することであるので、エントリポイント一旦即ち、適切な強調処理は、AOP AOPプロキシフレームが自動的に生成される定義:プロキシオブジェクトプロキシオブジェクト処理方法= +エンハンスメントである方法。

春AOPを実現使います

すべての書き込み私たちのビジネス・インタフェースと実装クラスの初

//抽象角色:增删改查业务
public interface UserService {
    int add();
    int delete();
    int update();
    void query();
}
//真实对象,完成增删改查操作的人
public
class UserServiceImpl implements UserService {
    @Override
    public int add() {
        System.out.println("增加一个用户");
        return 1;
    }

    @Override
    public int delete() {
        System.out.println("删除一个用户");
        return 1;
    }

    @Override
    public int update() {
        System.out.println("更新一个用户");
        return 1;
    }

    @Override
    public void query() {
        System.out.println("查找一个用户");
    }
}

AOPを実現するには、3つの方法

1.春のAPIによって実装

強化されたクラス

強化された書き込み二つのクラス、事前通知、春が提供するインタフェースを実装し、通知を掲載

//前置通知
public class BeforLog implements MethodBeforeAdvice {
    //method : 要执行的目标对象的方法
    //args : 被调用的方法的参数
    //target : 目标对象
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
//        System.out.println( target.getClass().getName() + "的" + method.getName() + "方法被执行了");
        if(!method.getName().equals("query")){
            System.out.println("开启事务...");
        }
    }
}
//后置通知
public class AfterLog implements AfterReturningAdvice {
    //returnValue 返回值
    //method被调用的方法
    //args 被调用的方法的对象的参数
    //target 被调用的目标对象
    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
//        System.out.println("执行了" + target.getClass().getName()
//                +"的"+method.getName()+"方法,"
//                +"返回值:"+returnValue);
        if(!method.getName().equals("query")){
            System.out.println("关闭事务...");
        }
    }
}

プロファイル

名前付きbeans1.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">
    <bean id="beforLog" class="com.cong.pojo.BeforLog"/>
    <bean id="afterLog" class="com.cong.pojo.AfterLog"/>
    <bean id="userService" class="com.cong.pojo.UserServiceImpl"/>
    <aop:config>
        <!--切入点表达式,即需要增强的方法-->
        <aop:pointcut id="userPointcut" expression="execution(* com.cong.pojo.UserServiceImpl.*(..))"/>
        <!--执行环绕; advice-ref执行方法 . pointcut-ref切入点-->
        <aop:advisor advice-ref="beforLog" pointcut-ref="userPointcut"/>
        <aop:advisor advice-ref="afterLog" pointcut-ref="userPointcut"/>
    </aop:config>
</beans>

テスト

//spring的API
@Test
public void test1(){
    ApplicationContext context = new ClassPathXmlApplicationContext("beans1.xml");
    UserService userService = (UserService) context.getBean("userService");
    userService.query();
    userService.add();
    userService.update();
    userService.delete();
}

結果

查找一个用户
开启事务...
增加一个用户
关闭事务...
开启事务...
更新一个用户
关闭事务...
开启事务...
删除一个用户
关闭事务...

2.カスタマイズ機能強化クラス

アナログトランザクションクラス

public class MyTransaction {
    public void before(){
        System.out.println("开启事务...");
    }
    public void afterReturning(){
        System.out.println("关闭事务...");
    }
    public void afterThrowing(){
        System.out.println("出现异常...");
    }
    public void after(){
        System.out.println("最终通知...");
    }
}

異常手動で追加のupdate()メソッド

@Override
public int update() {
    int i  = 1/0;
    System.out.println("更新一个用户");
    return 1;
}

プロファイル

名前付きbeans2.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">
    <bean id="transaction" class="com.cong.pojo.MyTransaction"/>
    <bean id="userService" class="com.cong.pojo.UserServiceImpl"/>
    <aop:config>
        <!--切入点表达式,即需要增强的方法-->
        <aop:pointcut id="userPointcut" expression="execution(int com.cong.pojo.UserServiceImpl.*(..))"/>
        <!-- 配置切面,切面就是增强的过程中需要用到的类 -->
        <aop:aspect ref="transaction">
            <aop:before method="before" pointcut-ref="userPointcut"/>
            <aop:after-returning method="afterReturning" pointcut-ref="userPointcut"/>
            <aop:after-throwing method="afterThrowing" pointcut-ref="userPointcut"/>
            <aop:after method="after" pointcut-ref="userPointcut"/>
        </aop:aspect>
    </aop:config>
</beans>

テスト

//自定义
@Test
public void test2(){
    ApplicationContext context = new ClassPathXmlApplicationContext("beans2.xml");
    UserService userService = (UserService) context.getBean("userService");
    userService.query();
    userService.add();
    userService.delete();
    userService.update();//会出现异常
}

結果

それぞれ、事前通知方法は、開始点行わ方法により行われる、アドバイスや異常通知した後、最終的に通知し、見つけることができます

查找一个用户
开启事务...
增加一个用户
关闭事务...
最终通知...
开启事务...
删除一个用户
关闭事务...
最终通知...
开启事务...
出现异常...
最终通知...

3.メモ実現

クラスセクション

@Aspect//标记为切面类
public class AnnotationPointcut {
    //前置通知
    @Before("execution(int com.cong.pojo.UserServiceImpl.*(..))")
    public void before(){
        System.out.println("开启事务...");
    }

    //后置通知
    @AfterReturning("execution(int com.cong.pojo.UserServiceImpl.*(..))")
    public void afterReturning(){
        System.out.println("关闭事务...");
    }
    //异常通知
    @AfterThrowing("execution(int com.cong.pojo.UserServiceImpl.*(..))")
    public void afterThrowing(){
        System.out.println("出现异常...");
    }
    //最终通知
    @After("execution(int com.cong.pojo.UserServiceImpl.*(..))")
    public void after(){
        System.out.println("最终通知...");
    }
    //环绕通知
    //@Around
}

プロファイル

名前付きbeans3.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">
    <bean id="userService" class="com.cong.pojo.UserServiceImpl"/>
    <bean id="annotationPointcut" class="com.cong.pojo.AnnotationPointcut"/>
    <!--开启注解支持,自动代理-->
    <aop:aspectj-autoproxy/>
</beans>

テスト

//注解的
@Test
public void test3(){
    ApplicationContext context = new ClassPathXmlApplicationContext("beans3.xml");
    UserService userService = (UserService) context.getBean("userService");
    userService.query();
    userService.add();
    userService.delete();
    userService.update();//会出现异常
}

結果

Aは最終通告より前の投稿通知よりも、間違った順序で、ノートを達成することを平均ビット

あなたがAOPを実現するために注釈を使用したいのであれば、それはアドバイスを周りに使用するのが最適です

查找一个用户
开启事务...
增加一个用户
最终通知...
关闭事务...
开启事务...
删除一个用户
最终通知...
关闭事务...
开启事务...
最终通知...
出现异常...

拡張について<aop:aspectj-autoproxy/>

AOP名前空間によって<aop:aspectj-autoproxy />自動的にセクションを織り、これらのステートメントの春のコンテナ設定@aspectJ豆セクションのプロキシを作成します。

もちろん、春はまだ内部的に使用されるAnnotationAwareAspectJAutoProxyCreator自動プロキシ作成の作業のために、しかし、具体的な実装の詳細はされています<aop:aspectj-autoproxy />アップ隠されました

<aop:aspectj-autoproxy />proxy-target-classプロパティは、デフォルトでは動的プロキシ表示JDK織りが強化され、falseです。分布がある場合に<aop:aspectj-autoproxy poxy-target-class="true"/>、動的表示CGLIBは、補強剤技術を織ります。ターゲットクラスがインタフェースを宣言していない場合でも、でも、プロキシ・ターゲットクラスのセットの場合はfalseに、春には、自動的にCGLIBの動的なプロキシを使用します。

周りのアドバイスについて4

手動制御方法は、コード内で実行されたとき、我々は向上をもたらすことができる通知フレームワークを囲むスプリング。

例えば、ここではカスタムクラスメソッドの実装を強化AOP

ビジネスクラス

唯一の実行方法

public class AroundAdviceService {
    public void doSomething(){
        System.out.println("do something...");
    }
}

アナログ通知クラス

public class AroundLog {
    public void before(){
        System.out.println("前置通知...");
    }
    public void afterReturning(){
        System.out.println("后置通知...");
    }
    public void afterThrowing(){
        System.out.println("异常通知...");
    }
    public void after(){
        System.out.println("最终通知...");
    }
    public void around(){
        System.out.println("环绕通知...");
    }
}

プロファイル

名前付きbeans4.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">
    <bean id="aroundLog" class="com.cong.pojo.AroundLog"/>
    <bean id="aroundAdviceService" class="com.cong.pojo.AroundAdviceService"/>
    <aop:config>
        <!--切入点表达式,即需要增强的方法-->
        <aop:pointcut id="userPointcut" expression="execution(void com.cong.pojo.AroundAdvice.doSomething())"/>
        <!-- 配置切面,切面就是增强的过程中需要用到的类 -->
        <aop:aspect ref="aroundLog">
            <aop:before method="before" pointcut-ref="userPointcut"/>
            <aop:after-returning method="afterReturning" pointcut-ref="userPointcut"/>
            <aop:after-throwing method="afterThrowing" pointcut-ref="userPointcut"/>
            <aop:after method="after" pointcut-ref="userPointcut"/>
            <aop:around method="around" pointcut-ref="userPointcut"/>
        </aop:aspect>
    </aop:config>
</beans>

テスト

//环绕通知
@Test
public void test4(){
    ApplicationContext context = new ClassPathXmlApplicationContext("beans4.xml");
    AroundAdvice aroundAdvice = (AroundAdvice) context.getBean("aroundAdviceService");
    aroundAdvice.doSomething();
}

異常な結果

非常に奇妙な結果

前置通知...
环绕通知...
最终通知...
后置通知...

AOPの内側の周りにアドバイスをコメントアウトすると、結果は正常です

前置通知...
do something...
后置通知...
最终通知...

プローブ

問題:

私たちは周りのアドバイスを設定すると、エントリポイントメソッドが実行され、通知方法は実行されません。

理由:

通知コード、ダイナミック造影剤に囲まには周りの動的プロキシ予告明確なエントリポイントメソッドの呼び出し、および我々のコードを発見しました。

ソリューション:

ProceedingJoinPoint:Springフレームワークは、インターフェイスを提供してくれます。インターフェース)は(続行する方法があり、この方法は、明示的エントリポイントメソッドを呼び出すことと等価です。

インターフェイスは、Springフレームワークは、私たちは私たちのために使用するためのインタフェースの実装クラスを提供します。、プログラムの実行中に、囲まれたパラメータとして通知することができます

アドバイスを周りの達成

アドバイスの周りに書き換え

    public Object aroundAdvice(ProceedingJoinPoint proceedingJoinPoint){
        Object res;
        try {
            Object [] args = proceedingJoinPoint.getArgs();//得到方法执行所需的参数
            before();//前置通知
            res = proceedingJoinPoint.proceed(args);//明确调用业务层方法(通过切入点表达式配置)
            afterReturning();//后置通知
            return res;
        } catch (Throwable throwable) {
            afterThrowing();//异常通知
            throw new RuntimeException(throwable);
        }finally {
            after();//最终通知
        }
    }

設定ファイルは、他のすべての通知をコメントアウト

<bean id="aroundLog" class="com.cong.pojo.AroundLog"/>
    <bean id="aroundAdvice" class="com.cong.pojo.AroundAdvice"/>
    <aop:config>
        <!--切入点表达式,即需要增强的方法-->
        <aop:pointcut id="pointcut" expression="execution(void com.cong.pojo.AroundAdvice.doSomething())"/>
        <!-- 配置切面,切面就是增强的过程中需要用到的类 -->
        <aop:aspect ref="aroundLog">
            <aop:around method="aroundAdvice" pointcut-ref="pointcut"/>
        </aop:aspect>
    </aop:config>

、再び通常の結果を実行します

前置通知...
do something...
后置通知...
最终通知...

シミュレーション側面やアドバイスの実行

取り扱いからします。https://blog.csdn.net/qq_32331073/article/details/80596084

public class AspectAdviceInvokeProcess {
    public static void main(String[] args){
        try {
            //正常执行
            AspectInvokeProcess(false);
            System.out.println("=====分割线=====");
            //异常执行
            AspectInvokeProcess(true);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    
    /**
     * 切面执行过程
     * @param isException
     * @throws Exception
     */
    public static void AspectInvokeProcess(boolean isException) throws Exception{
        try {
            try {
                aroundAdvice(isException);
            } finally {
                afterAdvice();
            }
            afterReturningAdvice();
            return;
        } catch (Exception e) {
            afterThrowingAdvice(e);
            throw e;
            return;
        }   
    }
    
    /**
     * 环绕增强
     * @param isException
     * @throws Exception
     */
    private static void aroundAdvice(boolean isException) throws Exception {
        System.out.println("around before advice");
        try {
            JoinPoint_Proceed(isException);
        } finally {
            System.out.println("around after advice");
        }
    }
    
    /**
     * 编织后的接入点执行过程
     * @param isException
     */
    public static void JoinPoint_Proceed(boolean isException){
        beforeAdvice();
        targetMethod(isException);
    }
    
    /**
     * 前置增强
     */
    private static void beforeAdvice() {
        System.out.println("before advice");
    }

    /**
     * 目标方法
     * @param isException
     */
    private static void targetMethod(boolean isException) {
        System.out.println("target method 执行");
        if(isException)
            throw new RuntimeException("异常发生");
    }
    
    /**
     * 后置增强
     */
    private static void afterAdvice() {
        System.out.println("after advice");
    }

    /**
     * 正常返回增强
     */
    private static void afterReturningAdvice() {
        System.out.println("afterReturning");
    }

    /**
     * 异常返回增强
     * @param e
     * @throws Exception
     */
    private static void afterThrowingAdvice(Exception e) throws Exception {
        System.out.println("afterThrowing:"+e.getMessage());
    }
}

結果

around before advice
before advice
target method 执行
around after advice
after advice
afterReturning
=====分割线=====
around before advice
before advice
target method 执行
around after advice
after advice
afterThrowing:异常发生
java.lang.RuntimeException: 异常发生

おすすめ

転載: www.cnblogs.com/ccoonngg/p/12026768.html