web-dev-qa-db-fra.com

Comment utiliser l'annotation Spring @Lookup?

Je dois obtenir un prototype de singleton. J'ai trouvé que l'injection de méthode est la voie à suivre, mais je ne sais pas vraiment comment utiliser l'annotation Spring @Lookup.

Je suis nouveau dans l'injection de dépendance et j'ai choisi la configuration des annotations. J'aimerais donc poursuivre dans cette voie.

J'ai découvert que l'annotation @Lookup avait été ajoutée récemment ( https://spring.io/blog/2014/09/04/spring-framework-4-1-ga-is-here ), mais je ne peux pas trouver n'importe où comment l'utiliser.

Donc, voici un exemple simplifié

Classe de configuration:

@Configuration
@Lazy
public class ApplicationConfiguration implements ApplicationConfigurationInterface {

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

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

Et voici un exemple de classe:

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

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

Comment faire cela avec l'annotation @Lookup?

12
Miljac

Avant d'appliquer l'annotation @Lookup à votre méthode public MyClass2 myClass2(), lisez ceci dans @ Javadoc de Lookup :

le conteneur générera des sous-classes d'exécution de la classe contenant la méthode via CGLIB, raison pour laquelle ces méthodes de recherche ne peuvent fonctionner que sur des beans que le conteneur instancie via des constructeurs normaux (c'est-à-dire que les méthodes lookup ne peuvent pas être remplacées sur des beans renvoyés à des méthodes d'usine nous ne pouvons pas leur fournir dynamiquement une sous-classe).

Supprimez donc la déclaration de bean de style de méthode d'usine suivante de ApplicationConfiguration:

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

et ajoutez l'annotation @Component pour laisser Spring instancier le bean (ajoutez également l'annotation @Lookup à la méthode):

@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
  }
}

Maintenant, récupérez le bean myClass1 hors contexte et sa méthode myClass2 aurait dû être remplacée/remplacée pour obtenir un nouveau bean prototype à chaque fois.


Mettre à jour:

Utiliser la déclaration de méthode d'usine

Il n'est pas difficile d'implémenter la méthode annotée @Lookup (la "méthode de recherche"). Sans @Lookup et en gardant votre classe de configuration inchangée, maintenant MyClass1 ressemble à (en fait, Spring génère une implémentation similaire dans une sous-classe si @Lookup était utilisé):

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 injecte la ApplicationContext pour vous.

28
qingbo

Si vous n'êtes pas sur Spring 4.1, vous pouvez utiliser l'injection de fournisseur:

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

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

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

Ceci est DI, IoC, évite les classes abstraites et les définitions XML pour les méthodes de recherche.

6
Josh

De plus, vous pouvez déclarer le bean myClass2 avec TARGET_CLASS proxyMode.

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