2012-11-08 21 views
6

Ich habe experimentiert mit Spring 3.1's bean definition profiles und verschachtelte Bohnen. Ich hatte gehofft, dass ich abhängig vom aktiven Profil verschiedene Bohnen definieren könnte. Betrachten Sie das folgende stark über vereinfachtes Beispiel so, dass mein Frühling Kontext enthält so etwas wieSpring 3.1 Bean Sichtbarkeit mit Bean Definitionsprofile

<bean id="say" class="test.Say" p:hello-ref="hello"/> 

<beans profile="prod"> 
    <bean id="hello" class="test.Hello" p:subject="Production!"/> 
</beans> 

<beans profile="dev"> 
    <bean id="hello" class="test.Hello" p:subject="Development!"/> 
</beans> 

ich die folgende Fehlermeldung erhalten:

Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'say' defined in class path resource [applicationContext.xml]: Cannot resolve reference to bean 'hello' while setting bean property 'hello'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'hello' is defined at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:328) at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:106) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1360) aJava Result: 1

Ich hatte erwartet, dass die hallo Bohne würde nach der definiert werden aktives Maven-Profil (in meinem Fall prod oder dev). Ich fange an zu denken, dass die aktiven Spring-Profile (spring.profiles.active) möglicherweise völlig unabhängig von Maven-Profilen sind.

Könnte jemand bitte erklären, wo ich falsch liege? (Ist das überhaupt möglich mit Profilen?).

Antwort

12

I was expecting that the hello bean would be defined according to the active Maven profile (in my case prod or dev). I'm starting to think that the Spring active profiles (spring.profiles.active) may be completely unrelated to Maven profiles.

Das stimmt, sie sind nicht verwandt.

Hier ist, wie man es beheben:

Stellen Sie sicher, dass die web.xml, die Sie in src/main/webapp/WEB-INF/ Ordner haben folgende Kontext Einstellung hat:

<context-param> 
    <param-name>spring.profile.active</param-name> 
    <param-value>${profileName}</param-value> 
</context-param> 

Und dann sicherstellen, dass die maven-war-plugin gedreht hat Filterung auf die web.xml:

<plugin> 
    <artifactId>maven-war-plugin</artifactId> 
    <version>2.3</version> 
    <configuration> 
     <filteringDeploymentDescriptors>true</filteringDeploymentDescriptors> 
    </configuration> 
</plugin> 

Und dann schließlich in Ihren Profilen:

<profiles> 
    <profile> 
     <id>dev</id> 
     <properties> 
      <profileName>dev</profileName> 
     </properties> 
    </profile> 
    <profile> 
     <id>prod</id> 
     <properties> 
      <profileName>prod</profileName> 
     </properties> 
    </profile> 
</profiles> 

Sie könnten auch einen Standardwert in der normalen Eigenschaften Abschnitt hinzufügen:

<properties> 
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 
    <profileName>dev</profileName> 
</properties> 

Also, wenn Sie ohne die -P Option läuft das dev Federprofil verwendet werden.

Wenn mvn package ausgeführt wird, hat der web.xml den korrekten Wert für spring.profile.active.

+0

Dank maba, gibt es eine schöne Möglichkeit, spring.profiles.active außerhalb der Webanwendung zu verwenden? z.B. für Komponententests –

+1

Wenn Sie den Federtest verwenden, können Sie die Annotation \ @ActiveProfiles zusammen mit den anderen Standard-Federtest-Annotationen (\ @ContextConfiguration, etc ...) verwenden. In der Regel verwende ich dies, um Datenbank-Tests für verschiedene Umgebungen durchzuführen. Ich laufe einen gegen Derby während des "Test" Maven-Ziels und habe einen anderen Satz für Orakel, der für das Maintor "Integrationstest" läuft. Ich erstelle abstrakte Klassen, um die Tests und die \ contextConfiguration zu definieren und sie zu erweitern, und benutze @ActiveProfiles, um zu einem Unit- oder Integrationstest zu werden. – Matt

+0

Danke, ich war mit diesem Fall fest und du hast mich gerettet: D –

2

Dank maba (deren Antwort ich akzeptieren werde), fing ich an, darüber auf eine andere Weise nachzudenken.

ich die Eltern bean geändert haben „sagen“, weil sie faul initialisiert werden muss, weil, wenn es anfänglich die verschachtelten Bean Kontexten noch keine begegnet ist nicht vorhanden. So ist die neue Version fügt eine neue Bean und ändert die „sagen“ Definition, so dass sie nun wie folgt aussehen:

<bean class="test.InitProfile" p:profiles="dev"/> 

<bean id="say" class="test.Say" lazy-init="true" p:hello-ref="hello"/> 

Die neue InitProfile Bohne für den Aufbau der aktiven Profile ein InitializingBean verantwortlich ist.

Es enthält:

package test; 

import org.springframework.beans.BeansException; 
import org.springframework.beans.factory.InitializingBean; 
import org.springframework.context.ApplicationContext; 
import org.springframework.context.ApplicationContextAware; 
import org.springframework.context.ConfigurableApplicationContext; 
import org.springframework.util.StringUtils; 

public class InitProfile implements InitializingBean, ApplicationContextAware { 

    private ConfigurableApplicationContext ctx; 
    private String[] profiles; 

    public void setApplicationContext(ApplicationContext ac) throws BeansException { 
     ctx = (ConfigurableApplicationContext) ac; 
    } 

    public void setProfiles(String inprofiles) { 
     if (inprofiles.contains(",")) { 
      profiles = StringUtils.split(inprofiles, ","); 
     } else { 
      profiles = new String[]{inprofiles}; 
     } 
    } 

    public void afterPropertiesSet() throws Exception { 
     String[] activeProfiles = ctx.getEnvironment().getActiveProfiles(); 
     if (profiles != null && activeProfiles.length == 0) { 
      ctx.getEnvironment().setActiveProfiles(profiles); 
      ctx.refresh(); 
     } 
    } 
} 

Mit diesem Ansatz hat den zusätzlichen Vorteil, dass sie das aktive Federprofil einzustellen eine Eigenschaftendatei Classpath verwenden (dies kann je nach meinem aktiven Maven Profil unterscheiden). Ich mag diesen Ansatz auch, weil ich ihn sowohl für Webanwendungen als auch für Befehlszeilenanwendungen verwenden kann.