2016-03-30 15 views
1

Ich habe einige ähnliche Sätze Bohnen. Zum Beispiel könnte ich eine Verbindung zur Datenbank haben, Überwachung für diese Datenbank und DAO für diese Datenbank, Thread-Pool für diese Datenbank und so weiter. Und ich möchte diese Menge von Beans mehrmals im selben Kontext mit leicht unterschiedlichen Eigenschaften instanziieren (z. B. mit einem anderen Host-Namen). Ich möchte so etwas haben:Frühling: wie man die gleiche Konfiguration mehrmals wiederbenutzt


abstract class ContextTemplate { 
    abstract String dbHost(); 

    @Bean 
    DataSource dataSource() { return new DataSourceImpl(dbHost()); } 

    @Bean 
    DbMonitoring dbMonitoring() { return new DbMonitoring(dataSource()); }} 

    // and ten more db-specific beans 
} 

@Configuration(prefix = "primary-") 
class PrimaryDbContext extends ContextTemplate { 
    @Override 
    String dbHost() { return "primary.host"; } 
} 

@Configuration(prefix = "slow-reqs-") 
class SlowRequestsContext extends ContextTemplate { 
    @Override 
    String dbHost() { return "slow.requests.host"; } 
} 

@Configuration 
@Import({ 
    PrimaryContext.class, 
    SlowRequestsContext.class, 
}) 
class MyContext { 
} 

Mit dieser imaginären Konfiguration instanziiert ich mit Bohnen einen einzigen Kontext haben möchte primary-dataSource, primary-monitoring, slow-reqs-dataSource, slow-reqs-monitoring.

Der Punkt ist, dass jedes von PrimaryDbContext und SlowRequestsContext mehrere sehr ähnliche Bean-Definitionen in einem resultierenden Anwendungskontext ausgeben sollte.

Ist so etwas mit Spring möglich?

Bearbeiten: erstellt ein feature request in the Spring tracker.

+0

@mre Ich bezweifle es. Profile sollen Bohnen instanziieren. Ich muss Bohnen aus derselben Definition bedingungslos instanziieren. – stepancheg

+0

@ pczeus Prototyp wird nicht funktionieren. Ich muss Beans mit unterschiedlicher Konfiguration instanziieren: 'primary-dataSource' und' slow-reqs-dataSource' sollten mit unterschiedlichen Host-Parametern instanziiert werden. – stepancheg

+0

Leider können Sie dies nicht mit Konfigurationen tun. Die Standard-Bean-Benennungsstrategie gibt denselben Namen für Bean, der mit derselben Methode erstellt wurde. Das bedeutet, dass die letzte Konfiguration alle vorherigen Beans mit eigenen Beans entfernt. Aber .. Sie können Ihre Bohnen manuell registrieren. –

Antwort

1

Ich weiß, dass diese Lösung nicht wie Ihr Beispiel aussieht. Aber Sie können Bean-Namen nicht auf andere Weise ändern, nur manuell. Erstellen von benutzerdefinierten Fabrik Postprozessor:

public class DbRegistryPostProcessor implements BeanFactoryPostProcessor{ 

    private String hostName; 
    private String prefix; 

    public BeanFactoryPostProcessor(Strin prefix, String hostName){ 
     this.prefix = prefix; 
     this.hostName = hostName; 
    } 

    @Override 
    public void postProcessBeanFactory(ConfigurableListableBeanFactory factory) throws BeansException { 
     factory.registerSingleton(prefix+"dataSource", dataSource()); 
     factory.registerSingleton(prefix+"dbMonitoring", dbMonitoring()); 
    } 


    DataSource dataSource() { return new DataSourceImpl(hostName); } 

    DbMonitoring dbMonitoring() { return new DbMonitoring(dataSource()); }} 

    // and ten more db-specific beans 
} 

Und registrieren Postprozessoren in der Konfiguration:

@Configuration 
public class MyContext { 

    @Bean 
    public DbRegistryPostProcessor primaryDbProcessor(){ 
     return new DbRegistryPostProcessor("primary-", "primary.host"); 
    } 

    @Bean 
    public DbRegistryPostProcessor secondaryDbProcessor(){ 
     return new DbRegistryPostProcessor("secondary-", "secondary.host"); 
    } 

} 

Natürlich mit diesem Ansatz Ihre Bohnen nicht (mit PropertySourcesPlaceholderConfigurer zum Beispiel) von anderen Postprozessoren verarbeitet werden . Wenn Sie Beans benötigen, die von anderen Postprozessoren verarbeitet werden, können Sie die benutzerdefinierte BeanDefinitionRegistryPostProcessor anstelle von implementieren.

0

Dynamisch können Sie zwischen verschiedenen Datenquellen wechseln, indem Sie ein Flag beibehalten, das Sie ändern können, indem Sie ein Servlet drücken, das das Flag im Cookie- oder Anwendungskontextbereich setzt.

Nur eine Bean von ContextTemplate registrieren, die intern zwei ContextTemplate hält.

  • Instanziieren primären und sekundären ContextTemplate einmal
  • überschreiben die Methoden
  • entscheiden über Flag basiert.

Zum Beispiel:

@Component 
public class MyContextTemplate implements InitializingBean, ContextTemplate { 

    private ContextTemplate primary; 
    private ContextTemplate secondary; 

    @Override 
    public void afterPropertiesSet() { 
     // initialize primary and secondary ContextTemplate 
     // you can initialize them in default constructor of this class also 
    } 

    public DataSource dataSource() { 
     if(flat-set) { 
      return primary.dataSource(); 
     } 
     return secondary.dataSource(); 
    } 

    public DbMonitoring dbMonitoring() { 
     if(flat-set) { 
      return primary.dbMonitoring(); 
     } 
     return secondary.dbMonitoring(); 
    } 
    // implement other methods 
} 

Sie mehrere Bohne von ContextTemplate auch registrieren und MyContextTemplate als primary bean markieren das Auto-Verdrahtung Konflikt Problem zu beheben.


Denken Sie einige über der Entwurfsmuster, die nach Ihren Anforderungen passt:

Eine Momentaufnahme der staatlichen Muster:

enter image description here

+0

Das funktioniert nicht: Ich brauche beide 'DbMonitoring' Beans im Kontext (so könnten sie zum Beispiel von' ApplicationContext.getBeansOfType' entdeckt werden). – stepancheg

+0

Wie bereits erwähnt, können Sie beide ContextTemplate-Beans im Kontext zusammen mit der obigen zusätzlichen ContextTemplate-Bean registrieren. Machen Sie diese zusätzliche Bean als primäre Bean, um die automatische Verdrahtung zu lösen. – Braj

+0

danke, aber das ist nicht das, wonach ich gefragt habe. Ich muss die automatische Verkabelung nicht auflösen, aber ich brauchte alle Beans in einem Kontext. – stepancheg

Verwandte Themen