How to set spring active profiles with maven profiles

JavaSpringMavenSpring Profiles

Java Problem Overview


I have an application with maven as a build tool.

I am using maven profiles to set up different properties from different profiles.

What i would like to do is that all active profiles in maven will be ported to spring active profiles as well so i can reference them in bean signature (@profile). but i am not sure how to do it.

for example: consider the following maven setup

<profiles>
	<profile>
		<id>profile1</id>
		<activation>
			<activeByDefault>true</activeByDefault>
		</activation>
		<properties>
		</properties>
	</profile>
	<profile>
		<id>profile2</id>
		<properties>
		</properties>
	</profile>
	<profile>
		<id>development</id>
		<activation>
			<activeByDefault>true</activeByDefault>
		</activation>
 		<properties>
		</properties>
	</profile>
	<profile>
		<id>production</id>
		<properties>	
		</properties>
	</profile>
</profiles>

assuming i run maven with out specifying any other profiles i would like for spring to have profile1 and development as active profiles.

Java Solutions


Solution 1 - Java

There is a more elegant way to switch between 2 maven+spring profiles simultaneously.

First, add profiles to POM (pay attention - maven+spring profile is activated by single system variable):

<profiles>
	<profile>
		<id>postgres</id>
		<activation>
			<activeByDefault>true</activeByDefault>
			<property>
				<name>spring.profiles.active</name>
				<value>postgres</value>
			</property>
		</activation>
		<dependencies>
			<dependency>
				<groupId>postgresql</groupId>
				<artifactId>postgresql</artifactId>
				<version>9.1-901.jdbc4</version>
			</dependency>
		</dependencies>
	</profile>
	<profile>
		<id>h2</id>
		<activation>
			<property>
				<name>spring.profiles.active</name>
				<value>h2</value>
			</property>
		</activation>			
		<dependencies>
			<dependency>
				<groupId>com.h2database</groupId>
				<artifactId>h2</artifactId>
				<version>1.4.191</version>
			</dependency>
		</dependencies>
	</profile>
</profiles>

Second, set default profile for spring (for maven it is already set in POM). For web application, I inserted following lines to web.xml:

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

Third, add profile-dependent beans to your config. In my case (XML config), it is:

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
	<property name="dataSource" ref="mainDataSource" />
	<property name="jpaVendorAdapter">
		<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
	</property>
	<property name="jpaProperties" ref="hibProps"/>
	<property name="packagesToScan">
		<list>
			<value>my.test.model</value>
		</list>
	</property>
</bean>
...
<beans profile="postgres">
	<bean name="mainDataSource"
		class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName" value="org.postgresql.Driver" />
		<property name="url" value="jdbc:postgresql://127.0.0.1:5432/webchat" />
		<property name="username" value="postgres" />
		<property name="password" value="postgres" />
	</bean>
</beans>

<beans profile="h2">
	<bean name="mainDataSource"
		class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName" value="org.h2.Driver" />
		<property name="url" value="jdbc:h2:file:./newsdb;INIT=RUNSCRIPT FROM 'classpath:init.sql';TRACE_LEVEL_FILE=0" />
		<property name="username" value="sa" />
		<property name="password" value="" />
	</bean>
</beans>

Now it is possible to:

  • Run my web-app on Postgres DB with mvn jetty:run or mvn jetty:run -Dspring.profiles.active=postgres commands
  • Run my web-app on H2 DB with mvn clean jetty:run -Dspring.profiles.active=h2

Solution 2 - Java

The first thing you need is two properties files for keeping your configurations. The names of the files should match with the pattern application-{custom_suffix}.properties. Create them in the src/main/resources directory of your Maven project, next to the main application.properties file, which you’re going to use later to activate one of the others and to hold values shared by both profiles.

Then it’s time to modify your pom.xml. You need to define a custom property in each of your Maven profiles and set their values to match with suffixes of corresponding properties files that you want to load with a particular profile. The following sample also marks the first profile to run by default, but it’s not mandatory.

<profile>
    <id>dev</id>
    <properties>
        <activatedProperties>dev</activatedProperties>
    </properties>
    <activation>
        <activeByDefault>true</activeByDefault>
    </activation>
</profile>
<profile>
    <id>release</id>
    <properties>
        <activatedProperties>release</activatedProperties>
    </properties>
</profile>

Next, in the build section of the same file, configure filtering for the Resources Plugin. That will allow you to insert properties defined in the previous step into any file in the resources directory, which is the subsequent step.

<build>
    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <filtering>true</filtering>
        </resource>
    </resources></build>

Finally, add the following line to the application.properties.

spring.profiles.active=@activatedProperties@

When the build is run, the Resources Plugin will replace the placeholder with the value of the property defined in the active Maven profile. After starting your application, the Spring framework will load the appropriate configuration file based on the name of the active Spring profile, which is described by the value of the spring.profiles.active property. Note that Spring Boot 1.3 replaced the default Resources Plugin syntax for filtered values and uses @activatedProperties@ instead of ${activatedProperties} notation.

It worked to perfection. Hope this can help you.

Solution 3 - Java

You'll have to filter a resources of your application, for instance a property file, that holds the information of which profile to activate in spring.

For instance

spring.profile = ${mySpringProfile}

And for each profile, define a value for this variable (mySpringProfile).

During the build, this will be filtered accordingly to the value defined in the currently active profile.

Then during the bootstrap of your application you'll select the appropriated profile according to this file (can't help you more as you didn't gave us more information, but this is quite easy.

Note: I can't find a way to get the currently active profile in maven (something like project.profiles.active that holds your -P values), that's why you'll have to set a new variable for each profile.

Note 2: if you are running a web application, instead of using this intermediate file, filter this value in your web.xml

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

Note 3: This is actually a bad practice, and you should set the profile at runtime with a system property

Solution 4 - Java

For a Spring Boot application, one can add a property in the Maven profile in pom.xml and then reference that property in application.properties.

Add Maven profiles to pom.xml with, for example, a property called spring.profile.from.maven:

<profiles>
	<profile>
		<id>postgres</id>
		<activation>
			<activeByDefault>true</activeByDefault>
		</activation>
		<properties>
			<spring.profile.from.maven>postgres</spring.profile.from.maven>
		</properties>
		<dependencies>
			<dependency>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-starter-data-jpa</artifactId>
			</dependency>
			<dependency>
				<groupId>org.postgresql</groupId>
				<artifactId>postgresql</artifactId>
				<scope>runtime</scope>
			</dependency>
		</dependencies>
	</profile>
	<profile>
		<id>noDb</id>
        <properties>
            <spring.profile.from.maven>noDb</spring.profile.from.maven>
        </properties>
	</profile>
</profiles>

Reference the Maven property in application.properties:

spring.profiles.include[email protected]@

With this setup, running maven with the postgres Maven profile or with no profile adds the postgres Spring profile to the list of Spring's active profiles, while running maven with the noDb Maven profile adds the noDb Spring profile to the list of Spring's active profiles.

Solution 5 - Java

Add placeholder ${activeProfile} in web.xml:

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

Set properties in pom.xml for each profile:

<profiles>
  <profile>
    <id>profile1</id>
    <activation>
      <activeByDefault>true</activeByDefault>
    </activation>
    <properties>
      <activeProfile>profile1</activeProfile>
    </properties>
  </profile>
  <profile>
    <id>profile2</id>
    <properties>
      <activeProfile>profile2</activeProfile>
    </properties>
  </profile>
</profiles>

Add maven-war-plugin and set <filteringDeploymentDescriptors>true</filteringDeploymentDescriptors> to replace the placeholder when running mvn package -Pprofile1 or mvn package -Pprofile2:

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

Solution 6 - Java

I'm currently building a small webapp that (due to reasons beyond my control) has to be capable of running on an old server/container that only supports Servlet 2.5 and Java 6. There is also a requirement for the webapp configuration to be completely self-contained, so even system variables and/or JVM parameters cannot be used. The administrator just wants a .war file for each environment that can be dropped into the container for deployment.

I'm using Spring 4.x in my webapp. This is how I configured my application such that the active Maven profile is used to set the active Spring 4.x profile.


pom.xml file changes

I added the following bits to my POM file. My POM is using model version 4.0.0 and I'm running Maven 3.1.x when I do my builds.

<modelVersion>4.0.0</modelVersion>

...

<profiles>
	<profile>
		<id>dev</id>
		<activation>
			<!-- Default to dev so we avoid any accidents with prod! :) -->
			<activeByDefault>true</activeByDefault>
		</activation>
		<properties>
			<!-- This can be a single value, or a comma-separated list -->
			<spring.profiles.to.activate>dev</spring.profiles.to.activate>
		</properties>
	</profile>
	<profile>
		<id>uat</id>
		<properties>
			<!-- This can be a single value, or a comma-separated list -->
			<spring.profiles.to.activate>uat</spring.profiles.to.activate>
		</properties>
	</profile>
	<profile>
		<id>prod</id>
		<properties>
			<!-- This can be a single value, or a comma-separated list -->
			<spring.profiles.to.activate>prod</spring.profiles.to.activate>
		</properties>
	</profile>
</profiles>

...

<build>
	<plugins>
		<plugin>
			<groupId>org.apache.maven.plugins</groupId>
			<artifactId>maven-war-plugin</artifactId>
			<version>2.6</version>
			<configuration>
				<webResources>
					<webResource>
						<filtering>true</filtering>
						<directory>src/main/webapp</directory>
						<includes>
							<include>**/web.xml</include>
						</includes>
					</webResource>
				</webResources>
				<failOnMissingWebXml>true</failOnMissingWebXml>
			</configuration>
		</plugin>
		...
	</plugins>
</build>

web.xml file changes

<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Setup for root Spring context
-->
<listener>
	<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
	<param-name>contextConfigLocation</param-name>
	<param-value>/WEB-INF/spring-core-config.xml</param-value>
</context-param>
<!--
Jim Tough - 2016-11-30
Per Spring Framework guide: http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#beans-environment

...profiles may also be activated declaratively through the spring.profiles.active 
property which may be specified through system environment variables, JVM system 
properties, servlet context parameters in web.xml, or even as an entry in JNDI.
-->
<context-param>
	<param-name>spring.profiles.active</param-name>
	<param-value>${spring.profiles.to.activate}</param-value>
</context-param>
<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->

Now I can create Java-based configuration classes like the one below that will only be used when a particular Spring profile is active.

@Configuration
@Profile({"dev","default"})
@ComponentScan
@EnableTransactionManagement
@EnableSpringDataWebSupport
public class PersistenceContext {
    // ...
}

Solution 7 - Java

spring boot plugin itself can help:

  <profiles>
    <profile>
      <id>postgres</id>
      <build>
        <plugins>
          <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
              <jmxPort>9001</jmxPort>
              <environmentVariables>
                <SPRING_PROFILES_ACTIVE>postgres</SPRING_PROFILES_ACTIVE>
              </environmentVariables>
            </configuration>
          </plugin>
        </plugins>
      </build>
    </profile>
    <profile>
      <id>h2</id>
      <build>
        <plugins>
          <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
              <jmxPort>9002</jmxPort>
              <environmentVariables>
                <SPRING_PROFILES_ACTIVE>h2</SPRING_PROFILES_ACTIVE>
              </environmentVariables>
            </configuration>
          </plugin>
        </plugins>
      </build>
    </profile>
  </profiles>

Solution 8 - Java

In the spring boot application, there are several ways to set profiles (dev, uat, prod, etc.)

For exmaple : You can add this in your property file:

spring.profiles.active=dev

Programmatically:

SpringApplication.setAdditionalProfiles("dev");

To specify what profiles are active, use this line

@ActiveProfiles("dev")

In a Unix environment

export spring_profiles_active=dev

Running the jar file with the dev profile.

java -jar -Dspring.profiles.active=dev JARNAME.jar

here JARNAME.jar means your application's jar

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionGleebView Question on Stackoverflow
Solution 1 - JavaEugeneView Answer on Stackoverflow
Solution 2 - JavaSergio Sánchez SánchezView Answer on Stackoverflow
Solution 3 - JavapoussmaView Answer on Stackoverflow
Solution 4 - JavaSayadiView Answer on Stackoverflow
Solution 5 - JavaxxgView Answer on Stackoverflow
Solution 6 - JavaJim ToughView Answer on Stackoverflow
Solution 7 - JavaMaksim KostrominView Answer on Stackoverflow
Solution 8 - JavaRuhul AminView Answer on Stackoverflow