skip to Main Content

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.ymland 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


  1. 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:

    $ java -jar spring-boot-demo.jar --spring.profiles.active=dev
    

    or

    $ java -Dspring.profiles.active=dev -jar spring-boot-demo.jar 
    

    An example to demonstrate the usage of spring boot profiles


    1. Define data inside src/main/resources/application-dev.properties (or .yml)

      File name: application-dev.properties

      myData=development-profile


    1. Fetch data using @Value annotation in Java class

      @Value("${myData}")
      private String myData;

      // ….
      System.out.println("myData = " + myData);
      // …


    1. 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/

    Login or Signup to reply.
  2. 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:

    enter image description here

    Then again add back the profiles part and load maven changes again.

    The required profile should start loading again.

    profiles part example:

    <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>
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search