23

自動配線時に奇妙な動作が発生する

このような同様のコードがあり、動作します

@Controller
public class Class1 {
    @Autowired
    private Class2 object2;
    ...
}

@Service
@Transactional
public class Class2{
   ...
}

問題は、Class2 がインターフェイスを実装する必要があるため、Class2 のみを変更したため、次のようになっていることです。

@Controller
public class Class1 {
    @Autowired
    private Class2 object2;
    ...
}

@Service
@Transactional
public class Class2 implements IServiceReference<Class3, Long>{
   ...
}

public interface IServiceReference<T, PK extends Serializable> {
    public T reference(PK id);
}

このコードで私はorg.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type for Class2. 注釈または iを削除すると問題がなくなり、Bean が注入されるため、注釈@Transitionalはインターフェイスと互換性がないようです(ただし、このクラスには両方が必要です)。クラスではなくメソッドに注釈を入れた場合にも発生します。@Transitionalmplements IServiceReference<Class3, Long>@Transitional

これが役立つ場合は、Spring 3.0.2 を使用します。

トランザクショナル メソッドとのインターフェイスに互換性がありませんか? 春のバグでしょうか?

4

3 に答える 3

28

問題は、Class1 が Class2 の具体的な参照ではなく、IServiceReference への参照を必要とすることです。

@Controller
public class Class1 {
@Autowired
private IServiceReference object2;
    ...
}

これは、Spring が @Transactional とマークしたクラスの動的プロキシを作成しているためです。したがって、Class2 が作成されると、明らかに Class2 型ではなく IServiceReference 型の Proxy オブジェクトにラップされます。

プロキシ サポートで Class2 を使用する動作が必要な場合は、CGLIB をオンにする必要があります。以下を参照してください。

スプリングスのドキュメントから:

Spring AOP はデフォルトで、AOP プロキシに標準の J2SE 動的プロキシを使用します。これにより、任意のインターフェイス (または一連のインターフェイス) をプロキシできるようになります。

Spring AOP は CGLIB プロキシも使用できます。これは、インターフェイスではなくクラスをプロキシするために必要です。ビジネス・オブジェクトがインターフェースを実装していない場合、デフォルトで CGLIB が使用されます。クラスではなくインターフェイスにプログラムすることをお勧めします。通常、ビジネス クラスは 1 つ以上のビジネス インターフェイスを実装します。インターフェイスで宣言されていないメソッドを通知する必要がある場合や、プロキシ化されたオブジェクトを具体的な型としてメソッドに渡す必要がある場合 (まれであることを願っています) では、CGLIB の使用を強制することができます。

Spring AOP がプロキシベースであるという事実を把握することは重要です。この実装の詳細が実際に何を意味するのかを完全に調べるには、セクション6.6.1「AOP プロキシについて」というタイトルのセクションを参照してください。

于 2010-04-26T11:41:26.763 に答える
13

アノテーションはTransactional、トランザクション セマンティクスを実装するために、Spring にアノテーション付き Bean の周りにプロキシ オブジェクトを生成するように指示します。生成されたプロキシは、ターゲット Bean と同じインターフェースを実装します。したがって、ターゲット Bean が を実装IServiceReferenceしている場合、生成されたプロキシも実装されます。

ターゲット Bean に実装されたインターフェースがない場合、生成されたプロキシは代わりにターゲット Bean タイプのサブクラスになります。

元の例では、インターフェイスを実装していないClass2ため、トランザクション プロキシは のサブクラスになります。実装にClass2変更すると、生成されたプロキシは拡張されなくなり、代わりに実装されました。これにより、.Class2IServiceReferenceClass2IServiceReferenceClassCastException

この状況に対する最善のアプローチは、 からClass1への参照を削除しClass2、代わりにClass2純粋にそのインターフェースを介して と通信することです。Class2好きなだけインターフェイスを実装できますが、プロキシはそれらすべてを実装します。

インターフェースに関係なく、Spring にサブクラス プロキシを強制的に生成させることができますが、複雑さが増すため、お勧めしません

于 2010-04-26T11:52:23.233 に答える
1

追加することで、強制的にプロキシにすることができます

@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)

このドキュメントも参照してください。

于 2012-07-17T15:22:05.770 に答える