ホームページ  >  記事  >  Java  >  JavaのSpringAopの詳しい説明

JavaのSpringAopの詳しい説明

黄舟
黄舟オリジナル
2017-10-08 09:34:091405ブラウズ

ここ数日間 SpringAop について勉強していて、インターネットでいくつかの情報を見つけました。このリンクは元のリンクです http://www.cnblogs.com/xrq730/p/4919025.html

AOP

AOP。 (Aspect Oriented Programming)、つまりアスペクト指向プログラミングは、OOP(Object Oriented Programming、オブジェクト指向プログラミング)を補完・改良したものと言えます。 OOP では、カプセル化、継承、ポリモーフィズムなどの概念を導入して、パブリック動作のコレクションをシミュレートするために使用されるオブジェクト階層を確立します。ただし、OOP を使用すると、開発者は垂直方向の関係を定義できますが、ロギング関数などの水平方向の関係を定義するのには適していません。ログ コードは、多くの場合、すべてのオブジェクト階層にわたって水平に分散されており、セキュリティ、例外処理、無関係な永続性など、他の種類のコードにも同様に当てはまります。これは OOP 設計ではクロスカッティングと呼ばれ、大量のコードの重複につながり、さまざまなモジュールの再利用に役立ちません。

AOP テクノロジーはその逆で、「クロスカッティング」と呼ばれるテクノロジーを使用して、カプセル化されたオブジェクトの内部を解剖し、複数のクラスに影響を与えるパブリックな動作を再利用可能なモジュールにカプセル化し、それを「アスペクト」と名付けます。という側面です。いわゆる「アスペクト」は、ビジネスとは何の関係もない単純にカプセル化されたロジックまたは責任ですが、システム内のコードの重複を減らし、モジュール間の結合を減らし、容易にするためにビジネス モジュールによって共同で呼び出されます。将来の操作性とメンテナンス性。

「横断的」テクノロジーを使用して、AOP はソフトウェア システムを 2 つの部分、中核的懸念事項横断的懸念事項に分割します。業務処理のメインプロセスが中心的な関心事であり、それとあまり関係のない部分が横断的な関心事です。横断的な関心事の特徴として、中核的な関心事の中で複数の場所で発生することが多く、権限認証やログ、モノなど基本的に場所が似ていることが挙げられます。 AOP の役割は、システム内のさまざまな懸念事項を分離し、中核的な懸念事項と横断的な懸念事項を分離することです。

AOP のコアコンセプト

1. 横断的な懸念事項

どのメソッドが傍受されるか、およびそれらにどのように対処するか?これらの懸念事項は、横断的な懸念事項と呼ばれます

2. クラスは、オブジェクトの特性の抽象化、アスペクトは横断的な関心事の抽象化です

3. Joinpoint (joinpoint)

インターセプトポイント、Spring ではメソッド型の接続ポイントのみがサポートされているため、Spring のジョインポイントはインターセプトされたメソッドを指します。実際、接続ポイントはフィールドまたはコンストラクターにすることもできます

4. ポイントカット (pointcut)

接続ポイントのインターセプトの定義

5. アドバイス (アドバイス)

いわゆる通知 実行されるコードを指します。接続ポイントをインターセプトした後の通知は、事前通知、事後通知、最終通知、および周囲の通知の 5 つのカテゴリに分類されます

6. ターゲット オブジェクト

プロキシのターゲット オブジェクト

7.

ターゲット オブジェクトにアスペクトを適用し、プロキシ オブジェクトの作成に至るプロセス

8. はじめに

コードを変更せずに、

実行時

またはフィールド

中にいくつかのメソッドをクラスに動的に追加できます。

Spring の AOP サポート

Spring の AOP プロキシは Spring の IOC コンテナによって生成および管理され、その依存関係も IOC コンテナによって管理されます。したがって、AOP プロキシはコンテナ内の他の Bean インスタンスをターゲットとして直接使用でき、この関係は IOC コンテナの依存関係注入によって提供できます。 Spring のプロキシ作成ルールは次のとおりです:

1, デフォルトでは、AOP プロキシの作成に Java 動的プロキシが使用されます。そのため、任意のインターフェイス インスタンスに対してプロキシを作成できます

2, 必要なクラスがbe proxied はプロキシ インターフェイスではありません。Spring は CGLIB プロキシ の使用に切り替えるか、CGLIB

の使用を強制することができます。AOP プログラミングを見ると、プログラマは次の 3 つの部分に参加するだけで済みます。 1. 共通のビジネス コンポーネントを定義します

2. 1 つのエントリ ポイントが複数のビジネス コンポーネントにまたがる可能性があります

3. 拡張処理は、通常のビジネス コンポーネントの AOP フレームワークに組み込まれた処理アクションです。したがって、AOP プログラミングの鍵は、エントリ ポイントを定義し、拡張処理を定義することです。適切なエントリ ポイントと拡張処理が定義されると、AOP フレームワークは AOP プロキシ、つまり、次のように自動的に生成します。

プロキシ オブジェクトのメソッド =強調処理+プロキシオブジェクトのメソッド

以下は Spring AOP です。その前に、Spring AOP を使用してコードを正常に実行するには、Spring が開発者に提供する jar パッケージを使用するだけでは十分ではありません。オンラインで 2 つの追加の jar をダウンロードしてください。パッケージ:

1、aopalliance.jar2、aspectjweaver .jar

Spring AOP を使用した 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"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">
            
</beans>
2 つのインターフェイス実装クラスを定義します:

1 public interface HelloWorld
2 {
3     void printHelloWorld();
4     void doPrint();
5 }
public class HelloWorldImpl1 implements HelloWorld
{
    public void printHelloWorld()
    {
        System.out.println("Enter HelloWorldImpl1.printHelloWorld()");
    }
    
    public void doPrint()
    {
        System.out.println("Enter HelloWorldImpl1.doPrint()");
        return ;
    }
}

印刷時間は次のとおりです:

public class HelloWorldImpl2 implements HelloWorld
{
    public void printHelloWorld()
    {
        System.out.println("Enter HelloWorldImpl2.printHelloWorld()");
    }
    
    public void doPrint()
    {
        System.out.println("Enter HelloWorldImpl2.doPrint()");
        return ;
    }
}

3 つのクラスが簡単な Spring AOP を実装できます。 aop.xml の構成を見てください。

public class TimeHandler
{
    public void printTime()
    {
        System.out.println("CurrentTime = " + System.currentTimeMillis());
    }
}

呼び出す main 関数を作成します。


CurrentTime = 1446129611993Enter HelloWorldImpl1.printHelloWorld()
CurrentTime = 1446129611993CurrentTime = 1446129611994Enter HelloWorldImpl1.doPrint()
CurrentTime = 1446129611994CurrentTime = 1446129611994Enter HelloWorldImpl2.printHelloWorld()
CurrentTime = 1446129611994CurrentTime = 1446129611994Enter HelloWorldImpl2.doPrint()
CurrentTime = 1446129611994

看到给HelloWorld接口的两个实现类的所有方法都加上了代理,代理内容就是打印时间

基于Spring的AOP使用其他细节

1、增加一个横切关注点,打印日志,Java类为:

public class LogHandler
{
    public void LogBefore()
    {
        System.out.println("Log before method");
    }
    
    public void LogAfter()
    {
        System.out.println("Log after method");
    }
}

aop.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"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">
        
        <bean id="helloWorldImpl1" class="com.xrq.aop.HelloWorldImpl1" />
        <bean id="helloWorldImpl2" class="com.xrq.aop.HelloWorldImpl2" />
        <bean id="timeHandler" class="com.xrq.aop.TimeHandler" />
        <bean id="logHandler" class="com.xrq.aop.LogHandler" />
        
        <aop:config>
            <aop:aspect id="time" ref="timeHandler" order="1">
                <aop:pointcut id="addTime" expression="execution(* com.xrq.aop.HelloWorld.*(..))" />
                <aop:before method="printTime" pointcut-ref="addTime" />
                <aop:after method="printTime" pointcut-ref="addTime" />
            </aop:aspect>
            <aop:aspect id="log" ref="logHandler" order="2">
                <aop:pointcut id="printLog" expression="execution(* com.xrq.aop.HelloWorld.*(..))" />
                <aop:before method="LogBefore" pointcut-ref="printLog" />
                <aop:after method="LogAfter" pointcut-ref="printLog" />
            </aop:aspect>
        </aop:config>
</beans>

测试类不变,打印结果为:

CurrentTime = 1446130273734
Log before method
Enter HelloWorldImpl1.printHelloWorld()
Log after method
CurrentTime = 1446130273735

CurrentTime = 1446130273736
Log before method
Enter HelloWorldImpl1.doPrint()
Log after method
CurrentTime = 1446130273736

CurrentTime = 1446130273736
Log before method
Enter HelloWorldImpl2.printHelloWorld()
Log after method
CurrentTime = 1446130273736

CurrentTime = 1446130273737
Log before method
Enter HelloWorldImpl2.doPrint()
Log after method
CurrentTime = 1446130273737

要想让logHandler在timeHandler前使用有两个办法:

(1)aspect里面有一个order属性,order属性的数字就是横切关注点的顺序,数字越大执行越靠后,后置通知相反。

(2)把logHandler定义在timeHandler前面,Spring默认以aspect的定义顺序作为织入顺序

2、我只想织入接口中的某些方法

修改一下pointcut的expression就好了:

<?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"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">
        
        <bean id="helloWorldImpl1" class="com.xrq.aop.HelloWorldImpl1" />
        <bean id="helloWorldImpl2" class="com.xrq.aop.HelloWorldImpl2" />
        <bean id="timeHandler" class="com.xrq.aop.TimeHandler" />
        <bean id="logHandler" class="com.xrq.aop.LogHandler" />
        
        <aop:config>
            <aop:aspect id="time" ref="timeHandler" order="1">
                <aop:pointcut id="addTime" expression="execution(* com.xrq.aop.HelloWorld.print*(..))" />
                <aop:before method="printTime" pointcut-ref="addTime" />
                <aop:after method="printTime" pointcut-ref="addTime" />
            </aop:aspect>
            <aop:aspect id="log" ref="logHandler" order="2">
                <aop:pointcut id="printLog" expression="execution(* com.xrq.aop.HelloWorld.do*(..))" />
                <aop:before method="LogBefore" pointcut-ref="printLog" />
                <aop:after method="LogAfter" pointcut-ref="printLog" />
            </aop:aspect>
        </aop:config>
</beans>

表示timeHandler只会织入HelloWorld接口print开头的方法,logHandler只会织入HelloWorld接口do开头的方法

3、强制使用CGLIB生成代理

前面说过Spring使用动态代理或是CGLIB生成代理是有规则的,高版本的Spring会自动选择是使用动态代理还是CGLIB生成代理内容,当然我们也可以强制使用CGLIB生成代理,那就是5f4edcee1f0c5735c643ff3ca537e591里面有一个"proxy-target-class"属性,这个属性值如果被设置为true,那么基于类的代理将起作用,如果proxy-target-class被设置为false或者这个属性被省略,那么基于接口的代理将起作用。

以上がJavaのSpringAopの詳しい説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。