3

Notre projet utilise le DI/IoC de printemps, donc j'utilise autowiring pour injecter des haricots. Le programme doit transmettre des paramètres à un objet pendant son instanciation. Et les paramètres sont connus au moment de l'exécution (pas au moment de la compilation).Comment passer le paramètre constructeur en utilisant le câblage automatique à ressort?

Comment réaliser ceci en utilisant l'autowiring. L'exemple de code est comme ci-dessous.

interface - IMessage

package com.example.demo.services; 

public interface IMessage { 
     String message(String name); 
} 

Implementations-
SayHelloService

package com.example.demo.services; 

import org.springframework.stereotype.Service; 

@Service 
public class SayHelloService implements IMessage { 

    String id; 

    public SayHelloService(String id) { 
     super(); 
     this.id = id; 
    } 

    @Override 
    public String message(String name) { 
     return "Hello Dear User - " + name + ". Greeter Id: " + id ; 
    } 
} 

MasterService

package com.example.demo.services; 

import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.beans.factory.annotation.Qualifier; 
import org.springframework.stereotype.Service; 

@Service 
public class MasterService implements IMessage { 

    String creationTime; 

    MasterService() { 
     System.out.println("ms... default constructor"); 
     creationTime = Long.toString(System.currentTimeMillis()); 
    } 

    //classic java way of creating service 
    IMessage sayHelloServiceClassicWay = new SayHelloService(creationTime); 

    //how to achieve above using spring auto wiring. Below code does not exactly do same. 
    @Autowired 
    @Qualifier("sayHelloService") 
    IMessage sayHelloServiceAutoWired; 

    @Override 
    public String message(String name) { 
     return name.toString(); 
    }  
} 

maintenant dans le programme ci-dessus (en MasterService) comment remplacer

iMessage sayHelloServiceClassicWay = new SayHelloService (creationTime);

avec code équivalent au ressort.

+0

Créez un getter et un setter pour la variable, puis utilisez la méthode setter dans le champ autowired. – user641887

+0

Dans votre fichier XML de configuration, spécifiez la propriété "creationTime" dans le bean de SayHelloService en tant que constructeur-arg. Le printemps l'autowire. – Coder

+0

@ user641887, pourriez-vous ajouter du code plz. – samshers

Répondre

1

Cela fonctionne différemment, créez SayHelloService dans le contexte Spring avec les arguments construct, puis Spring le fera automatiquement. No-xml congif exemple:

class B1 { 
    @Autowired 
    B2 b2; 
} 

class B2 { 
    B2(int i) { 
    } 
} 

@Configuration 
class Config { 

    @Bean 
    B1 b1() { 
     return new B1(); 
    } 

    @Bean 
    B2 b2() { 
     return new B2(1); 
    } 
} 

Dans cet exemple Le printemps B2 qui a lier automatiquement constructeur avec un arg

+0

pouvez-vous s'il vous plaît ajouter du code à la démo. Et ce sera l'exécution. En outre mon projet ne voulait pas éviter xml config. Mais de toute façon, partagez ce que vous voulez. – samshers

+0

thx pour répondre. L'extrait de code 'return new B2 (1);' value '1' est encore temps de compilation, j'ai besoin de le passer à l'exécution. – samshers

+0

il n'est pas nécessaire de compiler l'heure, vous pouvez prendre cette valeur à partir d'une propriété. Mais si vous dites que vous avez besoin d'injecter un bean (B2) à l'exécution - vous pouvez le faire par programmation, Spring n'est pas utile, l'initialisation du ressort est faite lors de la construction du contexte –

2

Spring ne fonctionne pas de cette façon. Vos deux beans sont trop couplés, à la fois en termes d'exécution et d'instanciation: lorsque le premier est créé, il crée lors de sa construction, le second et lui passe une valeur générée à l'exécution dans le constructeur d'arguments.

Même en jouant avec l'ordre d'injection de dépendance (@DependsOn, @Order ou deux @Configuration dont l'un dépend de l'autre), il ne résoudrait pas votre problème en raison de la valeur générée d'exécution qui n'est pas une dépendance.

Pour résoudre ce problème, en fournissant un procédé pour évaluer une fois creationTime dans l'interface IMessage peut être acceptable.
SayHelloService pourrait ressembler à:

package com.example.demo.services; 

import org.springframework.stereotype.Service; 

    @Service 
    public class SayHelloService implements IMessage { 

     String id; 

     public SayHelloService(String id) { 
      super(); 
      this.id = id; 
     } 

     @Override 
     public void setId(String id){ 
      // you can add this check to enforce the immutability of id 
      if (this.id != null){//exception handling} 
      this.id = id; 
     } 

     @Override 
     public String message(String name) { 
      return "Hello Dear User - " + name + ". Greeter Id: " + id ; 
     } 
    } 

Et vous pourriez changer MasterService de cette façon:

private IMessage sayHelloServiceAutoWired; 

@Autowired 
MasterService(@Qualifier("sayHelloService") 
IMessage sayHelloServiceAutoWired) { 
    System.out.println("ms... default constructor"); 
    creationTime = Long.toString(System.currentTimeMillis()); 
    this.sayHelloServiceAutoWired = sayHelloServiceAutoWired; 
    this.sayHelloServiceAutoWired.setId(creationTime); 
} 

PS: Le constructeur de autowiring n'est pas obligatoire mais il est plus propre que l'absence d'API pour définir des dépendances de la classe. Vous pouvez également utiliser un setter.

+0

gr8 répondre à nouveau. Je vois toujours que l'autowiring sur le constructeur est la voie à suivre. Sinon autowiring sur setter pourrait être autre choix. – samshers

+0

@samshers Merci. J'ai essayé de l'améliorer un peu. Les raisons du problème n'étaient pas assez claires. Setter est également possible mais il fournit plus de "droits" à la classe de client. Si ce n'est pas un problème, c'est valide. – davidxxx