web-dev-qa-db-ja.com

Spring @Lookupアノテーションを使用するには?

シングルトンからプロトタイプクラスを取得する必要があります。メソッドインジェクションが適切な方法であることがわかりましたが、Spring @Lookupアノテーションの使用方法がわかりません。

依存性注入は初めてなので、アノテーション構成を選択したので、その方向に進みたいと思います。

@Lookupアノテーションが最近追加されたことがわかりました( https://spring.io/blog/2014/09/04/spring-framework-4-1-ga-is-here )、しかし、それを使用する方法はどこにも見つかりません。

だから、これは簡単な例です

構成クラス:

@Configuration
@Lazy
public class ApplicationConfiguration implements ApplicationConfigurationInterface {

  @Bean
  public MyClass1 myClass1() {
    return new ContentHolderTabPaneController();
  }

  @Bean
  @Scope("prototype")
  public MyClass2 myClass2() {
    return new SidebarQuickMenuController();
  }
}

そしてここにクラスの例があります:

public class MyClass1 {
  doSomething() {
    myClass2();
  }

  //I want this method to return MyClass2 prototype
  public MyClass2 myClass2(){
  }
}

@Lookupアノテーションを使用するにはどうすればよいですか?

14
Miljac

_@Lookup_アノテーションをpublic MyClass2 myClass2()メソッドに適用する前に、これを @ LookupのJavadoc で読んでください。

コンテナは、CGLIBを介してメソッドを含むクラスのランタイムサブクラスを生成します。そのため、そのようなルックアップメソッドは、コンテナが通常のコンストラクタを通じてインスタンス化するBeanでのみ機能します(つまり、ルックアップメソッドはBeanで置き換えられません)ファクトリメソッドから返されます。これらのサブクラスを動的に提供することはできません)。

したがって、次のファクトリメソッドスタイルBean宣言をApplicationConfigurationから削除します。

_  @Bean
  public MyClass1 myClass1() {
    return new ContentHolderTabPaneController();
  }
_

そして_@Component_アノテーションを追加して、SpringがBeanをインスタンス化できるようにします(メソッドに_@Lookup_アノテーションも追加します):

_@Component
public class MyClass1 {
  doSomething() {
    myClass2();
  }

  //I want this method to return MyClass2 prototype
  @Lookup
  public MyClass2 myClass2(){
    return null; // This implementation will be overridden by dynamically generated subclass
  }
}
_

ここで、_myClass1_ Beanをコンテキスト外で取得し、その_myClass2_メソッドを置き換えるかオーバーライドして、毎回新しいプロトタイプBeanを取得する必要があります。


更新

ファクトリメソッド宣言の使用

_@Lookup_アノテーション付きメソッド(「ルックアップメソッド」)を実装することは難しくありません。 _@Lookup_がなく、構成クラスを変更しない場合、_MyClass1_は次のようになります(実際、_@Lookup_が使用された場合、Springはサブクラスで同様の実装を生成します)。

_public class MyClass1 {
  doSomething() {
    myClass2();
  }

  //I want this method to return MyClass2 prototype
  @Autowired
  private ApplicationContext applicationContext;
  public MyClass2 myClass2() {
      return applicationContext.getBean(MyClass2.class);
  }
}
_

SpringがApplicationContextを注入します。

33
qingbo

Spring 4.1を使用していない場合は、代わりにプロバイダーインジェクションを使用できます。

public class MyClass1 {
  @Autowired
  private Provider<MyClass2> myClass2Provider;

  doSomething() {
    MyClass2 myClass2 = myClass2();
    myClass2.fooBar()
  }

  public MyClass2 myClass2(){
    return myClass2Provider.get();
  }
}

これはDI、IoCであり、ルックアップメソッドの抽象クラスとxml定義を回避します。

7
Josh

また、TARGET_CLASS proxyModeを使用してmyClass2 Beanを宣言することもできます。

  @Bean
  @Scope("prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
  public MyClass2 myClass2() {
    return new SidebarQuickMenuController();
  }
1