Spring Boot Managing Profiles with @Profile Annotation Example
Spring Profiles provides a way to segregate parts of your application configuration and make it only available in certain environments. This is particularly useful when configuring different environments like development and/or production. In the following tutorial we demonstrate how to manage spring profiles with @Profile annotation.
Project Structure
Our application has the following project structure. Note: we have four different application-${env}.yml property files. Each file represents properties for a different environment, except the application-common.yml which is included in every property file.
Maven Dependencies
We use Apache Maven to manage our project’s dependencies. As we are writing JUnit tests, we also included the org.springframework.boot:spring-boot-starter-test dependency.
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.memorynotfound.springboot</groupId> <artifactId>profiles</artifactId> <version>1.0.0-SNAPSHOT</version> <url>https://memorynotfound.com</url> <name>Spring Boot - ${project.artifactId}</name> <packaging>jar</packaging> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.3.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <finalName>l;spring-boot-profile-example</finalName> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
Application Environment Properties
We are configuring three environments: default, dev and prod. Each of these environments will include the application-common.yml properties file. We use different environment profiles to illustrate how to manage spring profiles using @Profile annotation.
The application-common.yml is used for common application properties.
app: name: common-profile-name
The application-default.yml has the following content.
spring: profiles: active: - default include: common app: email: [email protected]
The application-dev.yml has the following content.
spring: profiles: active: - dev include: common app: email: [email protected]
The application-prod.yml has the following content.
spring: profiles: active: - prod include: common app: email: [email protected]
Configurable Application Properties
Depending on the active spring profile usually set by spring.profiles.active, spring will load different configuration properties.
package com.memorynotfound.springboot; import org.springframework.boot.context.properties.ConfigurationProperties; @ConfigurationProperties("app") public class ApplicationProperties { private String name; private String email; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } @Override public String toString() { return "ApplicationProperties{" + "name='" + name + '\'' + ", email='" + email + '\'' + '}'; } }
Spring Boot – @Profile Example
We can also manage different spring components using the @Profile annotation.
package com.memorynotfound.springboot; public interface Configuration { String getName(); }
The @Profile annotation indicates which component’ll be injected. Here we added two profiles: dev and default.
package com.memorynotfound.springboot; import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Service; @Service @Profile({"dev", "default"}) public class DevelopmentConfiguration implements Configuration { @Override public String getName() { return "development profile"; } }
The @Profile annotation indicates which component’ll be injected. Here we added one profile: prod.
package com.memorynotfound.springboot; import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Service; @Service @Profile({"prod"}) public class ProductionConfiguration implements Configuration { @Override public String getName() { return "production profile"; } }
Bootstrap Spring Boot Application
We wrote a simple spring boot application that’ll print the properties configured in the active profile.
package com.memorynotfound.springboot; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.context.properties.EnableConfigurationProperties; import javax.annotation.PostConstruct; @SpringBootApplication @EnableConfigurationProperties(ApplicationProperties.class) public class Application { private static Logger logger = LoggerFactory.getLogger(Application.class); @Autowired private ApplicationProperties properties; @Autowired private Configuration configuration; public static void main(String... args) throws Exception { SpringApplication.run(Application.class, args); } @PostConstruct private void init(){ logger.info("Spring Boot - active profile: " + configuration.getName()); logger.info("Spring Boot - Choosing Your Profile and @Profile annotation example"); logger.info(properties.toString()); } }
Programatically Setting Profiles
If you want, you can set an additional spring profile programatically.
public static void main(String... args) throws Exception { SpringApplication app = new SpringApplication(Application.class); app.setAdditionalProfiles("common"); app.run(args); }
Building and Running Spring Boot Application
### Building application mvn clean package ### Running with maven mvn spring-boot:run -Drun.jvmArguments="-Dspring.profiles.active=prod" ### Running with java java -jar spring-boot-profile-example.jar --spring.profiles.active=prod
Console Output
The previous application run with the argument spring.profiles.active=prod prints the following output to the console.
. ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v1.5.3.RELEASE) 2017-05-30 13:48:26.808 INFO 26463 --- [ main] c.memorynotfound.springboot.Application : The following profiles are active: common,dev 2017-05-30 13:48:27.624 INFO 26463 --- [ main] c.memorynotfound.springboot.Application : Spring Boot - active profile: production profile 2017-05-30 13:48:27.624 INFO 26463 --- [ main] c.memorynotfound.springboot.Application : Spring Boot - Choosing Your Profile and @Profile annotation example 2017-05-30 13:48:27.624 INFO 26463 --- [ main] c.memorynotfound.springboot.Application : ApplicationProperties{name='common-profile-name', email='[email protected]'}
Unit Testing Spring Profiles with JUnit
We previously saw how to use spring profiles to manage environment properties. In the following section we’ll write unit tests using JUnit and spring-boot-test.
Spring Boot – JUnit profiles @ActiveProfiles
We can annotate the class using @ActiveProfiles to register the default active profile.
package com.memorynotfound.springboot.test; import com.memorynotfound.springboot.Configuration; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.junit4.SpringRunner; import static org.assertj.core.api.Assertions.assertThat; @SpringBootTest @ActiveProfiles("dev") @RunWith(SpringRunner.class) public class ConfigurationTest { @Autowired Configuration configuration; @Test public void testDevelopmentProfile(){ String name = configuration.getName(); assertThat(name).contains("development"); } }
Spring Boot – JUnit Application
Running the application we can pass the spring.profiles.active using different methods. In the fist test, we don’t provide any profile. Spring’ll automatically use the default profile, when no other profile is set. In the next test, we set the spring.profiles.active property using a system variable. In the last test we pass the --spring.profiles.active=prod argument to the main method of the application.
package com.memorynotfound.springboot.test; import com.memorynotfound.springboot.Application; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.springframework.boot.test.rule.OutputCapture; import static org.assertj.core.api.Assertions.assertThat; public class ApplicationTest { @Rule public OutputCapture outputCapture = new OutputCapture(); @Before public void before() { System.clearProperty("spring.profiles.active"); } @Test public void testDefaultProfile() throws Exception { Application.main(); assertThat(getConsoleOutput()) .contains("[email protected]") .contains("common-profile-name"); } @Test public void testDevelopmentProfile() throws Exception { System.setProperty("spring.profiles.active", "dev"); Application.main(); assertThat(getConsoleOutput()) .contains("[email protected]") .contains("common-profile-name"); } @Test public void testProductionProfile() throws Exception { Application.main("--spring.profiles.active=prod"); assertThat(getConsoleOutput()) .contains("[email protected]") .contains("common-profile-name"); } private String getConsoleOutput(){ return outputCapture.toString(); } }
Download
From:一号门
COMMENTS