web-dev-qa-db-ja.com

Spring AOPでのプロキシの使用

Spring AOPでAspectJサポートを有効にすることについて述べた本を読んでいます。

以下に、本から抜粋した段落を示します。

Spring IoCコンテナーでAspectJアノテーションサポートを有効にするには、Bean構成ファイルで空のXML要素aop:aspectj-autoproxyを定義するだけです。次に、Springは、AspectJアスペクトに一致するBeanのプロキシを自動的に作成します。

アプリケーションの設計でインターフェイスが利用できないか使用されていない場合、CGLIBに依存してプロキシを作成することが可能です。CGLIBを有効にするには、proxy-target-class=trueで属性<aop:aspectj-autoproxy />を設定する必要があります。


2番目の段落を取得できません。 「インターフェイスは利用できません」が意味するもの。誰かがこれを例で説明できますか?

22
user2434

Spring AOPは、JDK動的プロキシまたはCGLIBを使用して、ターゲットオブジェクトのプロキシを作成します。

Springのドキュメントによると、ターゲットが少なくとも1つのインターフェースを実装している場合、JDK動的プロキシが使用されます。ただし、ターゲットオブジェクトがインターフェイスを実装していない場合は、CGLIBプロキシが作成されます。

これは、CGLIBプロキシの作成を強制する方法です(set proxy-target-class = "true")。

 <aop:config proxy-target-class="true">
    <!-- other beans defined here... -->
 </aop:config>

AspectJとそのautopoxyサポートを使用する場合、CGLIBプロキシを強制することもできます。これは<aop:aspectj-autoproxy>が使用され、ここでも「proxy-target-class」をtrueに設定する必要があります。

<aop:aspectj-autoproxy proxy-target-class="true"/>

詳細については、 Springを使用したアスペクト指向プログラミング のドキュメントのプロキシメカニズムのセクションを参照してください。

27
nowaq

Springは、JDK proxies を使用できるため、AOPのインターフェースを使用することを好みます。

たとえば、インターフェースMyServiceがあるとします。

public interface MyService {
    void doSomething();
}

そして実装MyServiceImpl

@Service
public class MyServiceImpl implements MyService {
    public void doSomething() {
        // does something!
    }
}

SpringがMyServiceのアスペクトを構成したことを検出すると、MyServiceを実装するJDKプロキシを作成し、MyServiceImpl Beanへのすべての呼び出しをプロキシしてアスペクト機能を追加します適切な場において。

JDKプロキシは、ターゲットオブジェクトと同じインターフェイスを実装し、その呼び出しを委任することで機能します。実装するインターフェースがない場合は機能しません。上記のようなインターフェースがない場合、SpringはCGLIBなどのバイトコードライブラリを使用して、アスペクト機能を組み込んだクラスを実行時に動的に作成する必要があります。

22
stevevls

ランタイムプロキシクラスを使用してAOP、キャッシュ、トランザクションがどのように機能するかを明確に説明するブログ here を見つけました。

インターフェイスにコーディングしていない場合(ブログのセクション「から引用)Beanクラスがインターフェイスを実装していない場合はどうしますか?」):

デフォルトでは、Beanがインターフェースを実装しない場合、Springは技術的な継承を使用します。起動時に、新しいクラスが作成されます。 Beanクラスから継承し、子メソッドに動作を追加します。このようなプロキシを生成するために、Springはcglibと呼ばれるサードパーティのライブラリを使用します。

7
Kumar Sambhav

Spring AOPは、横断的な懸念事項(別名アスペクト)を邪魔にならない方法で実装するメカニズムとしてプロキシを広範囲に使用します。基本的には、元の動作を強化するラッパーとしてプロキシを使用する、つまりトランザクション機能を追加するという考え方です。

これを実現するには、元のオブジェクトがインターフェースを実装するかどうかに応じて、2つのオプションがあります。

最初のケース(元のオブジェクトが少なくとも1つのインターフェースを実装する)では、リフレクションAPIの動的プロキシ機能を使用して、[〜#〜] implements [〜#〜]同じプロキシオブジェクトを作成します元のオブジェクトとインターフェースしているため、代わりにプロキシを使用できます。

2番目のケース(元のオブジェクトは[〜#〜] not [〜#〜]インターフェースを実装する)なので、より複雑なトリックを使用する必要があり、これがCGLIBが表示されたときです。プロジェクトページによると、「CGLIBは、Javaクラスを拡張し、実行時にインターフェイスを実装するために使用されます」。したがって、この場合のトリックは、プロキシを作成することです[〜#〜] extends [〜#〜]元のオブジェクトなので、代わりに使用できます。

5
Alejandro