it-swarm.com.de

Importieren Sie die Spring-Konfigurationsdatei basierend auf der Eigenschaft in der .properties-Datei

In meiner Spring XML-Konfiguration versuche ich, etwas in die richtige Richtung zu bringen:

<beans>

   <import resource="${file.to.import}" />

   <!-- Other bean definitions -->

</beans>

Ich möchte entscheiden, welche Datei basierend auf einer Eigenschaft in einer Eigenschaftendatei importiert werden soll .. Ich weiß, dass ich eine Systemeigenschaft verwenden kann, aber ich kann der JVM beim Start keine Eigenschaft hinzufügen.

Hinweis: Der PropertyPlaceHolderConfigurer wird nicht funktionieren. Importe werden aufgelöst, bevor BeanFactoryPostProcessors ausgeführt werden. Das Importelement kann nur System.properties auflösen.

Hat jemand eine einfache Lösung dafür? Ich möchte keine Unterklassen-Framework-Klassen starten und so weiter ...

Vielen Dank

33
nash2000

Das ist leider viel schwieriger als es sein sollte. In meiner Bewerbung habe ich dies folgendermaßen getan:

  1. Ein kleiner "Bootstrap" -Kontext, der für das Laden einer PropertyPlaceholderConfigurer-Bean zuständig ist, und einer anderen Bean, die für das Bootstrapping des Anwendungskontexts verantwortlich ist.

  2. Die oben erwähnte zweite Bean nimmt die "echten" Federkontextdateien zum Laden an. Ich habe meine Frühlingskontextdateien so organisiert, dass der konfigurierbare Teil an derselben Stelle bekannt ist. Zum Beispiel könnte ich 3 Konfigurationsdateien haben: one.onpremise.xml, one.hosted.xml, one.multitenant.xml. Die Bean lädt diese Kontextdateien programmgesteuert in den aktuellen Anwendungskontext.

Dies funktioniert, weil die Kontextdateien als Eingabe der Bean angegeben werden, die für das Laden verantwortlich ist. Es funktioniert nicht, wenn Sie nur versuchen, einen Import durchzuführen, wie Sie bereits erwähnt haben. Dies hat jedoch den gleichen Effekt, wenn Sie etwas mehr Arbeit benötigen. Die Bootstrap-Klasse sieht ungefähr so ​​aus:

 public class Bootstrapper implements ApplicationContextAware, InitializingBean {

    private WebApplicationContext context;
    private String[] configLocations;
    private String[] testConfigLocations;
    private boolean loadTestConfigurations;

    public void setConfigLocations(final String[] configLocations) {
        this.configLocations = configLocations;
    }

    public void setTestConfigLocations(final String[] testConfigLocations) {
        this.testConfigLocations = testConfigLocations;
    }

    public void setLoadTestConfigurations(final boolean loadTestConfigurations) {
        this.loadTestConfigurations = loadTestConfigurations;
    }

    @Override
    public void setApplicationContext(final ApplicationContext applicationContext) throws BeansException {
        context = (WebApplicationContext) applicationContext;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        String[] configsToLoad = configLocations;

        if (loadTestConfigurations) {
            configsToLoad = new String[configLocations.length + testConfigLocations.length];
            arraycopy(configLocations, 0, configsToLoad, 0, configLocations.length);
            arraycopy(testConfigLocations, 0, configsToLoad, configLocations.length, testConfigLocations.length);
        }

        context.setConfigLocations(configsToLoad);
        context.refresh();
    }
}

Rufen Sie im Grunde den Anwendungskontext ab, legen Sie die Konfigurationsorte fest und fordern Sie ihn auf, sich selbst zu aktualisieren. Das funktioniert perfekt in meiner Anwendung.

Hoffe das hilft.

15
Louis Marascio

Für den Frühling 2.5 und 3.0, ich habe eine ähnliche Lösung zu Louis, jedoch habe ich gerade über das kommende Feature von 3.1 gelesen: Property Management , was sich auch toll anhört.

6
István

Auf der Spring-JIRA gibt es ein altes Problem für das Hinzufügen von Properties-Platzhalter-Unterstützung für den Import (SPR-1358) , das als "Won't Fix" behoben wurde, aber seitdem wurde eine Lösung mit einem EagerPropertyPlaceholderConfigurer vorgeschlagen.

Ich habe Lobbying betrieben, um SPR-1358 wiedereröffnet zu haben, aber bisher keine Antwort. Vielleicht, wenn andere ihre Anwendungsfälle zu den Kommentaren hinzugefügt hätten, die zur Bewusstseinsbildung beitragen würden.

5
Ian Brandt

Warum nicht:

  1. lesen Sie Ihre Eigenschaftendatei beim Start
  2. dadurch wird festgelegt, welche Spring-Konfiguration geladen werden soll
  3. welche Federkonfiguration geladen ist, legt bestimmte Dinge fest, dann lädt eine gemeinsame Federkonfiguration

so invertieren Sie effektiv Ihre derzeit vorgeschlagene Lösung.

2
Brian Agnew

Fügen Sie etwas Ähnliches hinzu:

<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="ignoreResourceNotFound"><value>true</value></property>
    <property name="locations">
        <list>
            <value>classpath:propertyfile.properties</value>
        </list>
    </property>
</bean>
1
laz

Wenn Sie den importierten XML-Dateinamen außerhalb von applicationContext.xml angeben möchten, um applicationContext.xml zu ersetzen, ohne die Konfiguration des importierten XML-Dateipfads zu verlieren, können Sie einfach eine dazwischenliegende XML-Datei von Spring Beans hinzufügen, z. B. confSelector. xml, damit applicationContext.xml confSelector.xml importiert und confSelector.xml nur ein <import> -Element enthält, das auf die geeignete XML-Datei der benutzerdefinierten Beans verweist.

Eine andere Möglichkeit, die nützlich sein könnte, sind XML-Entitäten (definiert durch Hinzufügen von <! ENTITY ...> -Elementen in die DTD-Deklaration am Anfang von XML). Diese ermöglichen das Importieren von XML-Fragmenten aus anderen Dateien und stellen Funktionen für "Platzhalter" für jede XML-Datei bereit.

Bei keiner dieser Lösungen können Sie jedoch die Konfigurationsdatei im Java-Format .properties haben.

1
Jaan

Eine andere Problemlösung, die nicht auf Systemeigenschaften angewiesen ist, besteht darin, die Eigenschaften aller Dateien mit einem anderen PropertyPlaceholderConfigurer für jede Datei zu laden und für jede einzelne einen anderen Platzhalter-Präfix festzulegen. Dieser Platzhalter-Präfix wird durch die ursprüngliche Eigenschaftsdatei konfiguriert.



Definieren Sie die erste Eigenschaftsdatei: (entweder erste oder zweite)

globale.eigenschaften

fileToUse=first


Definieren Sie die Dateien, die eine Eigenschaft enthalten, die abhängig von der oben definierten Eigenschaft umgeschaltet werden kann:

erste.Eigenschaften

aProperty=propertyContentOfFirst

second.properties

aProperty=propertyContentOfSecond


.__ Definieren Sie dann die Platzhalter für alle Dateien:

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="locations">
        <list>
            <value>classpath:global.properties</value>
        </list>
    </property>
</bean>
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="placeholderPrefix" value="first{" />
    <property name="locations">
        <list>
            <value>classpath:first.properties</value>
        </list>
    </property>
</bean>
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="placeholderPrefix" value="second{" />
    <property name="locations">
        <list>
            <value>classpath:second.properties</value>
        </list>
    </property>
</bean>


Verwenden Sie die in global definierte Eigenschaft, um die zu verwendende Ressource aus der anderen Datei zu identifizieren:

${fileToUse}{aProperty}
0
Antoine Meyer

Wenn ich unten das JVM-Argument hinzufüge und die Datei myApplicationContext.dev.xml habe, wird der Frühling geladen

-DmyEnvironment = dev

<context:property-placeholder />

<import resource="classpath:/resources/spring/myApplicationContext.${myEnvironment}.xml"/>
0
gabbon

Die Antwort von André Schuster, auf die ich gestoßen bin, half mir, ein sehr ähnliches Problem zu lösen, das ich hatte, wenn ich einen anderen Ausdruck von Eigenschaften finden wollte, je nachdem, ob ich auf meinem eigenen Host, von Jenkins auf unserem Build-Host oder in einer "echten" Bereitstellung lief . Ich tat dies:

<context:property-placeholder location="file:///etc/myplace/database.properties" />

später gefolgt von

<bean id="propertyConfigurer"
      class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="locations">
        <list>
            <value>WEB-INF/classes/resources/database.properties</value>
            ...
        </list>
    </property>
</bean>

was mein Problem gelöst hat, weil ich auf meinem Entwicklungshost einen Link zu meiner eigenen Kopie von database.properties in /etc/myplace/database.properties und eine etwas andere auf dem Server mit Jenkins habe . In der realen Bereitstellung wird keine solche Datei gefunden. Spring greift also auf die "echte" in resources in meinem Klassendateiverzeichnis zurück. Wenn die betreffenden Eigenschaften bereits in der Datei in /etc/myplace/database.properties angegeben wurden, werden sie (zum Glück) nicht von der lokalen Datei neu definiert.

0
Russ Bateman