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?
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:
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.
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.
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();
}