Spring Profile

Spring profile allows conditional registration of beans/components in runtime based on constants specified declaratively in configuration or programmatically in code. Let see some use cases.

Activate @Component based on active profile

Suppose we have a service interface called SomeService which has a method called doSomething:

1
2
3
4
// In SomeService.java
public interface SomeService {
void doSomething();
}

SomeService should only do real work in production environment and trivials in others. We can do this way:

1
2
3
4
5
6
7
8
9
// In SomeServiceImpl.java
@Service
@Profile("production")
public class SomeServiceImpl implements SomeService {
@Override
public void doSomething() {
// Do real work ...
}
}
1
2
3
4
5
6
7
8
@Service
@Profile("!production")
public class NoOpSomeServiceImpl implements SomeService {
@Override
public void doSomething() {
// Do trivial things ...
}
}

Now, based on whether production profile is declared or not, SomeServiceImpl or NoOpSomeServiceImpl will serve requests as SomeService.

Register @Bean based on active profile

1
2
3
4
5
6
7
8
@Configuration
public class WebConfiguration {
@Bean
@Profile({"dev", "!featureA"})
public CustomBean customBean() {
// instantiate, configure and return bean ...
}
}

A bean with type CustomBean will be registered if profile dev is active or featureA is not active.

Testing accepted profiles through Spring Environment

Sometimes, it is considered be too heavy to switch whole bean/component based on active profile. We can use spring environment to test accepted profile.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import org.springframework.core.env.Environment;

// In SomeServiceImpl.java
@Service
@Profile("production")
public class SomeServiceImpl implements SomeService {
@Autowired
private Environment environment;

@Override
public void doSomething() {
if (environment.acceptsProfiles("featureA", "!featureB")) {
// Do things when featureA is active or featureB is not active.
}
// Do other work ...
}
}

If you are using Thymeleaf, you can do this:

1
2
3
4
5
6
7
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">

<script th:if="${@environment.acceptsProfiles('dev')}" type="text/javascript" src="//unpkg.com/[email protected]/dist/vue.js"></script>
<script th:if="${@environment.acceptsProfiles('!dev')}" type="text/javascript" src="//unpkg.com/[email protected]/dist/vue.min.js"></script>

</html>

Now, we knows how to use profile, let dig how to declare it.

Declare Spring profile in configuration file

In Spring Boot, you can declare profiles in application.properties or application.yml:

1
spring.profiles.active = dev,featureA

If you declare profiles this way, profiles specified outside application jar will override profiles inside application jar. If you want to declare a profile which can’t be overrode, use spring.profiles.include.

1
2
// application.properties inside projectA's jar
spring.profiles.include = projectA

application.properties is just one of places to specify spring configuration, you can delcare profiles in other places according to Spring Boot Externalized Configuration. Such as:

1
2
3
4
5
6
7
8
# os environment
SPRING_PROFILES_ACTIVE=featureB java -jar project.jar

# system properties
java -Dspring.profiles.active=featureB -jar project.jar

# command line arguments
java -jar project.jar --spring.profiles.active=featureB

Specify profiles programmatically

In application level, you can add profiles using SpringApplication.setAdditinalProfiles.

1
2
3
4
5
6
7
8
@SpringBootApplication
public class SomeApplication {
public static void main(String[] args) {
SpringApplication app = new SpringApplication(SomeApplication.class);
app.setAdditinalProfiles("someApplication")
app.run(args);
}
}

In library level, you can add/set profiles through ConfigurableEnvironment.

1
2
3
4
5
6
7
public class FeatureConfig implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext context) {
ConfigurableEnvironment environment = context.getEnvironment();
environment.addActiveProfile("featureB");
}
}
1
2
3
// In library's META-INF/spring.factories
org.springframework.context.ApplicationContextInitializer=\
path.to.library.package.FeatureConfig