I can’t activate a profile dynamically in a Spring Boot app. I defined profiles in pom.xml
as follows:
<profiles>
<profile>
<id>dev</id>
<properties>
<activatedProperties>dev</activatedProperties>
</properties>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
<profile>
<id>prod</id>
<properties>
<activatedProperties>prod</activatedProperties>
</properties>
</profile>
</profiles>
Then I created 2 files in src/main/resources
:
# application.yml
spring:
application:
name: myapp-service
profiles:
active: @activatedProperties@
server:
port: 8200
Here is application-dev.yml
:
spring:
kafka:
producer:
bootstrap-servers: localhost:9092
key-serializer: org.apache.kafka.common.serialization.StringSerializer
value-serializer: org.apache.kafka.common.serialization.StringSerializer
redis:
host: localhost
port: 6379
When starting the app from the IDE, it fails to read active: @activatedProperties@
values rating the error about @
symbol:
java.lang.IllegalStateException: Failed to load property source from target/classes/application.yml'
...
Caused by: org.yaml.snakeyaml.scanner.ScannerException: while scanning for the next token
found character '@' that cannot start any token. (Do not use @ for indentation)
in 'reader', line 5, column 13:
active: @activatedProperties@
^
I found some examples of the same use but in application.properties
file.
Isn’it possible to do the same in a yml
file ?
I tried to replace it with $
sign as follows:
...
profiles:
active: ${activatedProperties}
This time it is Spring Boot that raised the error about failing to load redis.host
value:
Factory method 'redisConnectionFactory' threw exception; nested exception is java.lang.IllegalArgumentException: Host name must not be null or empty!
as if the profile is not recognized.
Here is the configuration file:
@Configuration
@EnableConfigurationProperties
@ConfigurationProperties
public class AppConfiguration {
private String redisHost;
private int redisPort;
private String redisPassword;
... //getters and getters come here
Here is the Spring Boot application class:
@SpringBootApplication
public class LiveDataServiceApplication {
@Autowired
private AppConfiguration configuration;
public static void main(String[] args) {
SpringApplication.run(LiveDataServiceApplication.class, args);
}
@Bean
public RedisConnectionFactory redisConnectionFactory() {
RedisStandaloneConfiguration redisConfiguration = new RedisStandaloneConfiguration(configuration.getRedisHost(), configuration.getRedisPort());
redisConfiguration.setPassword(configuration.getRedisPassword());
return new LettuceConnectionFactory(redisConfiguration);
}
What am I missing?
UPDATE
I annotated every attribute in AppConfiguration
class with `@Value():
public class AppConfiguration {
@Value("${redis.host}")
private String redisHost;
@Value("${redis.port}")
private int redisPort;
@Value("${redis.password:}")
private String redisPassword;
...
and moved the values to application.yml
and it worked!
If I keep the vaues in application-dev.yml
file, it fails to load them.
Why so? It seems like the default profile dev
is not set.
UPDATE-2
Finally, it worked if I use a single YAML file application.yml
including available environments as follows:
spring:
application:
name: live-data-service
profiles:
active: ${activatedProperties}
kafka:
producer:
bootstrap-servers: localhost:9092
key-serializer: org.apache.kafka.common.serialization.StringSerializer
value-serializer: org.apache.kafka.common.serialization.StringSerializer
server:
port: 8200
redis:
host: localhost
port: 6379
---
spring:
profiles: prod
kafka:
producer:
bootstrap-servers: prod-kafka.server:9092
key-serializer: org.apache.kafka.common.serialization.StringSerializer
value-serializer: org.apache.kafka.common.serialization.StringSerializer
redis:
host: prod.server.com
port: 6379
password: prod-server-pwd
at least locally? I have no idea why id does not when using separate YAML files (application-dev.yml
, application-prod.yml
, etc.
Offcial Spring Boot docs have no more details about that.
2
Answers
The root cause of the problem is due to no having Spring Boot profile for the required environment.
The profile named ‘dev’ shown above (included in pom.xml) is a Maven profile, and not a spring profile. Therefore this will not be used for Spring configuration.
How to solve the problem?
The problem can be solved by explicitly creating separate Spring profile, and specifying it as a parameter, in these 2 steps:
Step 1: Create separate profile file for each environment (Example: dev / test)
Spring Boot uses a default profile named ‘default’.
Values for default profile will be read from
application.properties file or application.yml file.
Values for a new profile (Example: dev / prod / test) can be specified in separate file named
application-<profile_name>.[properties / yml]
For dev profile, the file will be
application-dev.properties or application-dev.yml
For test profile, the file will be
application-test.properties or application-test.yml
Step 2: Specify the profile name as a run-time parameter to Spring Boot application.
Profile name can be specified using
-Dspring.profiles.active=profile_name
or
--spring.profiles.active=profile_name
To run the ‘dev’ profile, the Spring boot app can be started using:
or
An example to demonstrate the usage of spring boot profiles
Define data inside src/main/resources/application-dev.properties (or .yml)
File name: application-dev.properties
myData=development-profile
Fetch data using
@Value
annotation in Java class@Value("${myData}")
private String myData;
// ….
System.out.println("myData = " + myData);
// …
Run the spring boot application using profile as a parameter
$ java -jar spring-boot-demo.jar --spring.profiles.active=dev
....
myData = development-profile
...
More information:
https://mkyong.com/spring-boot/spring-boot-profiles-example/
There is something wrong with maven change load.
You have to remove profiles part from pom.xml, then load maven changes by clicking on the icon:
Then again add back the profiles part and load maven changes again.
The required profile should start loading again.
profiles part example: