2016-11-22 9 views
3

Überlastung ich bin mit zwei Federn (4.2) Java-Konfigurationen, ein in einem Basismodul und eine in einem kundenspezifischen Modul:Wie richtig Spring-Bean-Konfiguration

@Configuration 
public class BaseConfig { 

    @Bean 
    public A getA() { 
     return new A("aaa"); 
    } 

} 

@Configuration 
public class ClientConfig { 

    @Bean 
    public A getA() { 
     return new A("bbbb"); 
    } 

} 

Während der App Last ist immer BaseConfig.getA() Wie kann ich die Basis-Bean-Factory-Konfiguration ändern, um einige Client-spezifische Dinge zu haben?

Antwort

2

Ich persönlich würde im Frühling niemals eine Bohne überschreiben! Ich habe gesehen, dass Leute zu viel Zeit damit verbracht haben, Probleme in diesem Zusammenhang zu debuggen. Aus dem gleichen Grund würde ich niemals @Primary verwenden. In diesem Fall

hätte ich 3 Kontexte

  1. Kontext, Bohnen einzigartig in der Elternkontext
  2. Kontext enthält, die Bohnen einzigartig für das Kind Kontext
  3. Zusammenfassung Kontext enthält, die alle gemeinsamen Bohnen enthält.

Auf diese Weise werden Sie die 2 Kontexte angeben, die geladen werden sollen. Dies könnte programmatisch oder unter Verwendung von Profilen erfolgen. Möglicherweise benötigen Sie mehr Kontexte, da Sie wahrscheinlich möchten, dass einige Ihrer Beans in Tests unterschiedlich sind.

+0

scheint die am besten geeignete Lösung, ich akzeptiere die Antwort, trotzdem wäre es schön zu wissen, warum die Basiskonfiguration statt der Client-spezifischen genommen wurde, wie definiert Spring die Reihenfolge und das Überschreiben von Beans beim Laden von Konfigurationsdateien? – simonC

+0

Wenn Sie zwei Konfigurationen haben, können Sie sie in zwei Kontexten laden, zuerst den übergeordneten und dann den untergeordneten. Das Kind kann Elternbohnen sehen, aber nicht umgekehrt. Auch –

+0

Ignorieren Sie den obigen Kommentar. Ich werde eine zusätzliche Antwort schreiben, da Kommentare zu stackoverflow ziemlich lahm sind! –

0

Ich bin nicht sicher, wie Bean Config-Klassen zu erweitern. Eine Lösung besteht darin, die Bean in ClientConfig mit @Primary Annotation zu markieren. Dies führt dazu, dass die ClientConfig-Definition von Bean A verwendet wird.

+0

leider sieht dies nicht in meinem Fall arbeitet – simonC

0

Wenn Sie beide Konfigurationen enthalten können Sie primäre Anmerkung überprüfen: Primary

Zeigt an, dass eine Bohne Vorzug gegeben werden sollte, wenn mehrere Kandidaten qualifiziert sind, eine eindeutige Abhängigkeit autowire. Wenn genau eine "primäre" Bean unter den Kandidaten existiert, wird dies der autowired Wert sein.

+0

leider in meinem Fall nicht sieht – simonC

1

Ich denke, dass Sie einen Blick auf die @Profile Annotation werfen sollten. Sie könnten einfach Konfiguration in unterschiedliche Basis und Client-spezifische aufgeteilt wie:

@Configuration 
@Profile("base") 
public class BaseConfig { 

    @Bean 
    public A getA() { 
     return new A("aaa"); 
    } 

} 

@Configuration 
@Profile("client") 
public class ClientConfig { 

    @Bean 
    public A getA() { 
     return new A("bbbb"); 
    } 

} 

jetzt das spezifische Profil ausgeführt durch Zugabe von

  • @ActiveProfiles („Basis“) auf Anfrage Hauptmethode
  • Frühling. profiles.active = Bankeintrag in application.properties
  • oder auch Profilnamen in Jvm params passieren
+0

nicht anwendbar in meinem Fall arbeiten, müssen wir brauchen ein paar Bohnen wee, die auch in der Basis-Konfiguration definiert werden, würden wir nur außer Kraft setzen möchten spezifische Bean-Definitionen von der Basis. Während des Debuggens haben wir herausgefunden, dass die erste Konfiguration, die vom Frühling verarbeitet wird, die Client-spezifische ist und danach von der Basis überschrieben wird, wir brauchen genau das Gegenteil – simonC

+0

Ok. Wie wäre es damit: Markieren Sie ClientConfig mit @Profile ("config"), lassen Sie BaseConfig ohne Profile. In ClientConfig markieren Sie Ihre Bean mit @Primary und führen Sie die App mit dem Client-Profil aus. –

0

@Profile Annotation hierfür kann ...

verwendet werden
@Configuration 
@Profile("base") 
public class BaseConfig { 

    @Bean 
    public A getA() { 
     return new A("aaa"); 
    } 

} 

@Configuration 
@Profile("client") 
public class ClientConfig { 

    @Bean 
    public A getA() { 
     return new A("bbbb"); 
    } 

} 

Verwenden Sie den folgenden Link https://spring.io/blog/2011/02/14/spring-3-1-m1-introducing-profile/

0

Dies ist eine Antwort auf einen Kommentar oben, aber da Kommentare Formatierung und Größe haben nur begrenzte, Ich werde stattdessen mit einer Antwort antworten.

wie funktioniert Feder definiert die Reihenfolge und überwiegenden von Bohnen, wenn Konfigurationsdateien Laden

Es hängt davon ab, was Sie durch das Laden mehrere Konfiguration bedeuten. Wenn Sie einen Spring-Kontext haben und zwei Klassen mit @Configuration haben und einen Komponenten-Scan durchführen, dann erstellt Spring den Abhängigkeitsbaum, und welcher Kontext (Bean) auch immer geladen wird, definiert das Bean (da es die erste Definition überschreibt).

Wenn Sie mehrere Spring-Kontexte in einer übergeordneten untergeordneten Beziehung haben, dann werden die untergeordneten und übergeordneten Beans angezeigt, und überschreibt auch übergeordnete Beans, wenn Sie child.getBean (type.class) verwenden. Der Elternteil kann keine Bohne von Kindern sehen.

Verwenden von @Primary. Wenn Sie einen Spring-Kontext haben (kann aus mehreren Konfigurationen stammen), der zwei Beans desselben Typs definiert, können Sie context.getBean (type.class) oder @AutoWired (ohne @Qualifier) ​​nicht verwenden, da Sie mehrere Beans haben vom gleichen Typ. Dieses Verhalten kann geändert werden, wenn eine der Beans @Primary ist. Ich versuche, die Verwendung von @Primary in meinem eigenen Code zu vermeiden, aber ich kann sehen, es wird stark in Spring Boots Auto konfiguriert System verwendet, so denke ich, es hat eine subtile Verwendung, wenn es um das Design von Rahmen geht.

Hier ein kleines Beispiel: Wenn Sie Konfigurationsklassen direkt laden, benötigen sie nicht die Annotation @Configuration.

public class ParentChildContext { 

    public static void main(String[] args) { 
     parentChildContext(); 
     twoConfigurationsSameContext(); 

    } 

    private static void twoConfigurationsSameContext() { 

     ApplicationContext ctx = new AnnotationConfigApplicationContext(Parent.class, Child.class); 
     // if you have two beans of the same type in a context they can be loaded by name 
     Object childA = ctx.getBean("childA"); 
     System.out.println("childA = " + childA); 

     Object parentA = ctx.getBean("parentA"); 
     System.out.println("parentA = " + parentA); 
     // since both configurations define A, you can't do this 
     ctx.getBean(A.class); 
    } 

    private static void parentChildContext() { 
     ApplicationContext parentCtx = new AnnotationConfigApplicationContext(Parent.class); 

     A parentA = parentCtx.getBean(A.class); 
     System.out.println("parent = " + parentA); 

     AnnotationConfigApplicationContext childCtx = new AnnotationConfigApplicationContext(); 
     childCtx.register(Child.class); 
     childCtx.setParent(parentCtx); 
     childCtx.refresh(); 

     A childA = childCtx.getBean(A.class); 
     System.out.println("child = " + childA); 
    } 


    public static class Parent { 
     @Bean 
     //@Primary // if you enable @Primary parent bean will override child unless the context is hierarchical 
     public A parentA() { 
      return new A("parent"); 
     } 
    } 

    public static class Child { 
     @Bean 
     public A childA() { 
      return new A("child"); 
     } 
    } 


    public static class A { 
     private final String s; 

     public A(String s) { 
      this.s = s; 
     } 
     @Override 
     public String toString() { 
      return "A{s='" + s + "'}"; 
     } 
    } 
}