Injection dynamic de spring, modèle semblable à celui d’une usine

Une continuation de Dependency injection, praxis d’injection retardée . J’ai la classe principale:

package test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.stereotype.Component; import java.util.List; import java.util.Scanner; @Component public class Main { @Autowired private SsortingngValidator ssortingngValidator; @Autowired private SsortingngService ssortingngService; @Autowired private ValidationService validationService; public void main() { scanKeyboardCreateLists(); ssortingngValidator.validate(); final List validatedList = ssortingngValidator.getValidatedList(); for (Ssortingng currentValid : validatedList) { System.out.println(currentValid); } } private void scanKeyboardCreateLists() { //Let's presume the user interacts with the GUI, dynamically changing the object graph... //Needless to say, this is past container initialization... Scanner scanner = new Scanner(System.in); int choice = scanner.nextInt(); //Delayed creation, dynamic if (choice == 0) { ssortingngService.createList(); validationService.createList(); } else { ssortingngService.createSecondList(); validationService.createSecondList(); } } public static void main(Ssortingng[] args) { ApplicationContext container = new ClassPathXmlApplicationContext("/META-INF/spring/applicationContext.xml"); container.getBean(Main.class).main(); } } 

Et le graphe d’objects est créé dynamicment, en fonction de l’interaction de l’utilisateur. J’ai résolu le couplage d’application, ce qui m’a permis de le tester très simplement. De plus, étant donné que les listes sont gérées par le conteneur, le caractère dynamic de cette application (et des autres) est sans importance, car elles peuvent être demandées à tout moment si l’application en a besoin, en conservant leurs éléments.

Le rest du code est ici:

 package test; import java.util.List; public interface Ssortingngable { List getSsortingngList(); } package test; import org.springframework.stereotype.Component; import java.util.ArrayList; @Component public class SsortingngList extends ArrayList { } package test; import org.springframework.stereotype.Component; import javax.inject.Inject; import java.util.ArrayList; import java.util.List; @Component public class SsortingngService implements Ssortingngable { private List ssortingngList; @Inject public SsortingngService(final ArrayList ssortingngList) { this.ssortingngList = ssortingngList; } //Simplified public void createList() { ssortingngList.add("FILE1.txt"); ssortingngList.add("FILE1.dat"); ssortingngList.add("FILE1.pdf"); ssortingngList.add("FILE1.rdf"); } public void createSecondList() { ssortingngList.add("FILE2.txt"); ssortingngList.add("FILE2.dat"); ssortingngList.add("FILE3.pdf"); ssortingngList.add("FILE3.rdf"); } @Override public List getSsortingngList() { return ssortingngList; } } package test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.List; @Component public class SsortingngValidator { private List ssortingngList; private List validationList; private final List validatedList = new ArrayList(); @Autowired public SsortingngValidator(final ArrayList ssortingngList, final ArrayList validationList) { this.ssortingngList = ssortingngList; this.validationList = validationList; } public void validate() { for (Ssortingng currentSsortingng : ssortingngList) { for (Ssortingng currentValidation : validationList) { if (currentSsortingng.equalsIgnoreCase(currentValidation)) { validatedList.add(currentSsortingng); } } } } public List getValidatedList() { return validatedList; } } package test; import java.util.List; public interface Validateable { List getValidationList(); } package test; import org.springframework.stereotype.Component; import java.util.ArrayList; @Component public class ValidationList extends ArrayList { } package test; import org.springframework.stereotype.Component; import javax.inject.Inject; import java.util.ArrayList; import java.util.List; @Component public class ValidationService implements Validateable { private List validationList; @Inject public ValidationService(final ArrayList validationList) { this.validationList = validationList; } //Simplified... public void createList() { validationList.add("FILE1.txt"); validationList.add("FILE2.txt"); validationList.add("FILE3.txt"); validationList.add("FILE4.txt"); } public void createSecondList() { validationList.add("FILE5.txt"); validationList.add("FILE6.txt"); validationList.add("FILE7.txt"); validationList.add("FILE8.txt"); } @Override public List getValidationList() { return validationList; } } 

Est-ce que quelqu’un sait comment je résoudrais l’appel de méthode createList () ou createSecondList () – sans utiliser le constructeur qui force à peu près la conception? Je pensais à une usine, mais une usine pour chaque classe dans un projet de plus grande ampleur ne semble pas être une bonne idée.

Quelque chose comme:

  

Et dans la méthode factory, instanciez la classe et appelez la méthode createList (). Ou appelez-le comme ceci, depuis une méthode – ce qui, encore une fois, a l’air mauvais, forçant la méthode à avoir la responsabilité d’instancier le graphique d’object.

L’image des dépendances d’exécution que je veux résoudre en cours d’exécution est ci-dessous:

entrez la description de l'image ici

Existe-t-il un autre moyen d’utiliser le conteneur pour réaliser une initalisation dynamic paresseuse en fonction de l’interaction de l’utilisateur?

Je vous remercie.

Si vous souhaitez que certains membres de votre classe soient initialisés de manière dynamic \ remplis à chaque appel du getter correspondant, vous pouvez essayer la méthode d’injection, Lookup Method Injection. Lire pp. 3.3.4.1 ici .

Ainsi, même si la classe contenant le membre dynamic a été créée dans scope=singletone (valeur par défaut pour le conteneur de beans spring) à chaque fois que vous accéderez au champ auquel une méthode de recherche est affectée, vous obtiendrez un object approprié en fonction de la logique métier implémentée dans la méthode de recherche. Dans votre cas, la liste est une interface afin que vous puissiez facilement implémenter la validation dans votre méthode de recherche et renvoyer une liste validée.

Modifier:

J’ai trouvé un meilleur exemple dans la documentation de Spring – je pense que c’est très clair. Jetez un oeil à “3.4.6.1 Injection de méthode Lookup”

Lorsque vous configurez la classe Main , affectez une méthode de recherche à son membre List . Elle sera appelée chaque fois que vous aurez besoin d’une nouvelle instance du bean List .

Bonne chance!

Spring est conçu pour l’injection de composants réutilisables, pas pour la manipulation et l’injection de données commerciales.

En effet, certaines données sont utilisées dans l’dependency injection, mais uniquement pour configurer le comportement des composants, pas pour créer un détenteur de données métiers.

En passant, l’option suivante peut être utilisée dans votre cas: grâce à une interface BeanFactory avec BeanFactoryAware et à l’utilisation de scope = “prototype”, vous pouvez générer un bean en getBean() comme dans cet exemple ou à partir de cette autre question: création de haricot à la demande .

Une autre option si vous avez un nombre limité de haricots à préparer consiste à utiliser la création générique de haricots de la même manière que les haricots manquants.

Maintenant, considérons que Spring ne ramasse jamais les haricots dans son contexte. Il est donc risqué pour la consommation de mémoire de créer des beans Spring pour stocker des données commerciales.

Si votre objective est différent (j’espère), vous essayez peut-être de mettre en place vous-même un support multi-locataire. Spring fournit une location si vous avez un contexte commercial différent à implémenter avec des composants ou des comportements spécifiques.

Cela ressemble à un utilisateur qui peut choisir des graphiques 1..N d’objects et vous ne voulez charger que celui que l’utilisateur a sélectionné au moment de l’exécution. Si les graphiques sont connus au moment de la conception mais que l’utilisateur choisit simplement celui qu’ils veulent, il me semble que ce que vous avez est un tas de ApplicationContexts et que vous souhaitez uniquement charger le seul ApplicationContext que l’utilisateur a sélectionné au moment de l’exécution. Alors, pourquoi ne pas simplement définir le jeu de ApplicationContexts et ensuite instancier le bon au moment de l’exécution. Comme Spring prend en charge Java Config, il peut être judicieux de définir ces configurations en tant que classes Java afin que vous puissiez obtenir un inheritance et éviter de couper / coller du code.