100

In my application I have beans annotated with @Profile("prod") and @Profile("demo"). The first one, as you can guess :), is used on beans that connect to production DB and second one annotates beans that use some fake DB (HashMap or whatever)- to make development faster.

What I would like to have is default profile ("prod") that will be used always if it is not overridden by "something-else".

Perfect would be to have in my web.xml:

<context-param>
     <param-name>spring.profiles.active</param-name>
     <param-value>prod</param-value>
</context-param>

and then override this with -Dspring.profiles.active="demo" so that I could do:

mvn jetty:run -Dspring.profiles.active="demo". 

But sadly this is not working. Any idea how could I achive that? Setting -Dspring.profiles.active="prod" on all my environments is not an option.

Michał Margiel
  • 2,912
  • 4
  • 20
  • 19

7 Answers7

111

Define your production environment as default profile in your web.xml

<context-param>
   <param-name>spring.profiles.default</param-name>
   <param-value>prod</param-value>
</context-param>

and if you want to use a different profile pass it as system property

mvn -Dspring.profiles.active="demo" jetty:run
andih
  • 5,570
  • 3
  • 26
  • 36
  • 3
    No he tried to define the **active** profile in the web.xml and as system property. In my solution I configure a **default** profile in the web.xml and overwrite/define the *active* profile via system property. If there is no explicit *active* profile the default will be used. – andih Apr 06 '12 at 10:01
  • 1
    Thanks! this is exactly what I wanted! couldn't find it anywhere :/ – Michał Margiel Apr 06 '12 at 10:04
  • One problem with this approach: if you set `spring.profiles.default=prod` in `application.properties`, then `application-prod.properties` will not be loaded. This is counter-intuitive. – gamliela Jul 31 '16 at 08:55
  • @gamliela The approach does not set the default profile in an `application.properties` file. In order to know that `application-prod.properties` should be use you'll have to know the profile. That's what this approach does. It defines profiles outside the spring context either the `web.xml` (default) or via environment variable (overwrite the default). – andih Aug 01 '16 at 06:09
  • @andih Yes, I know that, but I only say it's not intuitive and therefore problematic. Since `application-default.properties` get loaded, I also expect that `application-newdefault.properties` will be loaded as well. It's not a problem with your solution, it's a problem with Spring... – gamliela Aug 01 '16 at 07:58
69

My experience is that using

@Profile("default")

the bean will only be added to the context if no other profile is identified. If you pass in a different profile, e.g. -Dspring.profiles.active="demo", this profile is ignored.

Kees de Kooter
  • 7,078
  • 5
  • 38
  • 45
Paul Philion
  • 706
  • 6
  • 2
  • 4
    The accepted answer depends on web.xml (and that's fine), but this answer works whether you have web.xml or not and so is more broadly useful to everybody. – Jason Apr 12 '15 at 16:10
  • 1
    this solution is much cleaner – cahen Apr 28 '15 at 14:07
  • @rustyx this is explained in the AbstractEnvironment API: https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/core/env/AbstractEnvironment.html#RESERVED_DEFAULT_PROFILE_NAME Spring Boot also mentions this behavior by the end of this section: https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-external-config-files-profile-specific – Gerardo Roza Feb 10 '21 at 13:22
6

I have the same issue, but I use WebApplicationInitializer in order to configure the ServletContext programmatically (Servlet 3.0+). So I do the following:

public class WebAppInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext sc) throws ServletException {
        // Create the 'root' Spring application context
        final AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
        // Default active profiles can be overridden by the environment variable 'SPRING_PROFILES_ACTIVE'
        rootContext.getEnvironment().setDefaultProfiles("prod");
        rootContext.register(AppConfig.class);

        // Manage the lifecycle of the root application context
        sc.addListener(new ContextLoaderListener(rootContext));
    }
}
mcoolive
  • 3,805
  • 1
  • 27
  • 32
5

You may also consider removing the PROD profile, and use @Profile("!demo")

blacelle
  • 2,199
  • 1
  • 19
  • 28
3

About setting default production profile already posted @andih

The easiest way to set default profile for maven jetty plugin, is to include below element in your plugin configuration:

<plugin>
    <groupId>org.eclipse.jetty</groupId>
    <artifactId>jetty-maven-plugin</artifactId>
    <configuration>
        <systemProperties>
            <systemProperty>
                <name>spring.profiles.active</name>
                <value>demo</value>
            </systemProperty>
        </systemProperties>
    </configuration>
</plugin>
Jakub Kubrynski
  • 13,724
  • 6
  • 60
  • 85
3

Spring provide two separate properties when determining which profiles are active:

  • spring.profiles.active

and

  • spring.profiles.default

If spring.profiles.active is set, then its value determines which profiles are active. But if spring.profiles.active isn't set, then Spring looks to spring.profiles.default.

If neither spring.profiles.active nor spring.profiles.default is set, then there are no active profiles, and only those beans that aren't defined as being in a profile are created.Any bean that does not specify a profile belongs to default profile.

Dherik
  • 17,757
  • 11
  • 115
  • 164
-1

You can setup your web.xml as filtered resource and have this value filled by maven from maven profile settings - that what we do.

in pom filter all resources (you can do taht if you have no ${} marking in them)

<webResources>
    <resource>
        <directory>src/main/webapp</directory>
        <filtering>true</filtering>
    </resource>
</webResources>

in web.xml put

<context-param>
     <param-name>spring.profiles.active</param-name>
     <param-value>${spring.prfile}</param-value>
</context-param>

in pom create maven profiles

<profiles>
    <profile>
        <id>DEFAULT</id>
        <activation>
            <activeByDefault>true</activeByDefault>
        </activation>
        <properties>
            <spring.profile>prod</spring.profile>
        </properties>
    <profile>
    <profile>
        <id>DEMO</id>
        <properties>
            <spring.profile>demo</spring.profile>
        </properties>
    <profile>
</profiles>

Now you can use

mvn jetty:run -P DEMO

or simply -P DEMO with any maven command

Hurda
  • 4,647
  • 8
  • 35
  • 49
  • 1
    I am not sure but I think that won't work. IMHO jetty:run will not run phase in which resources are filtered. – Michał Margiel Apr 06 '12 at 11:14
  • of caurse you need to run mvn clean compile jetty:run -P DEMO, but with uncompiled code it runs it autimaticly – Hurda Apr 06 '12 at 19:45
  • 10
    I understand that one of the main goals of Spring 3.1 Profiles is to generate a single WAR file ready to be deployed in all environments. Using Maven profiles is an step back to the previous state: where the packaging of a WAR file was needed for each environment... – edrabc Sep 03 '12 at 22:54
  • @edrabc he was asking for mvn jetty:run - there is no WAR file. – Hurda Jan 28 '13 at 17:01
  • Agree @Hurda. But he was also asking for running the command in multiple environments: having a mix of Maven Profiles and Spring Profiles could be a bit misleading... – edrabc Jan 31 '13 at 12:36