Execute Spring @EventListener based on a value from application.yaml

1.5k views Asked by At

I would like the execution of the event handler to depend on whether the property is set to true or false in application.yaml file. I have three yaml files (test, dev, prod) and I have set the settings in them:

application-dev.yml

page-cache:
  starting: false

application-test.yml

page-cache:
  starting: true

application-prod.yml

page-cache:
  starting: true

And I need not to write 'dev' or 'test' in condition myself, but to read true or false from yaml files.

For example: condition = "@serviceEnabled == true", does not work.

@Service
public class ServiceImpl {

    @Value("${page-cache.starting}")
    private Boolean serviceEnabled;

   // means that when running dev will be false and the method will not run and this code is working
    @EventListener(
        value = ApplicationReadyEvent.class,
        condition = "@environment.getActiveProfiles()[0] != 'dev'")
    public void updateCacheAfterStartup() {
        log.info("Info add starting...");
        someService.getInfo();
    }
}

I tried to do as in this article, but it doesn't work for me:

Evaluate property from properties file in Spring's @EventListener(condition = "...")

I also tried the same option

@Service
public class ServiceImpl {
    @Value("${page-cache.starting}")
    private Boolean serviceEnabled;
   
    public Boolean isServiceEnabled() {
        return this.serviceEnabled;
    }

    public Boolean getServiceEnabled() {
        return serviceEnabled;
    }

    @EventListener(
        value = ApplicationReadyEvent.class,
        condition = "@ServiceImpl.serviceEnabled")
    public void updateCacheAfterStartup() {
        log.info("Info add starting...");
        someService.getInfo();
    }
}
2

There are 2 answers

1
Dirk Deyne On BEST ANSWER
  1. Make sure the YAML format is correct in application-test.yml, application-prd.yml,...

    example:

    application-dev.yml

    page-cache:
       starting: false
    
  2. ServiceImpl must be a component/bean, so annotate your class with @Service, @Component or use @Bean if the instance is created in a @Configuration class.

Extra tip:

You could use condition = "! @environment.acceptsProfiles('dev')"

instead of condition = "@environment.getActiveProfiles()[0] != 'dev'"

that way the order of active profiles does not matter

or define when the condition is valid: condition = "@environment.acceptsProfiles('test', 'prod')"

UPDATE:

You could also directly use page-cache.starting in the condition.

@EventListener(
     value = ApplicationReadyEvent.class,
     condition = "@environment.getProperty('page-cache.starting')")
public void updateCacheAfterStartup() {
    // update the cache
}

Here updateCacheAfterStartup() will only be triggered at startup when page-cache.starting is true. If set to false or when not present the method will not be called.

If you want to force that page-cache.starting is provided (in all profiles) you should use: condition="@environment.getRequiredProperty('page-cache.starting')"

0
Ashok On

you can access the property using @Value in some class whose bean is created (either by annotations Component, Service, Configuration .. etc.). Use @EventListener(condition = "@beanName.youProperty"), the event is handled when the value of yourProperty is true or string having "true", "on", "yes", or "1" values.

if yourProperty is private and doesn't have getter also, then above will fail. yourProperty on the bean should be either public or should have getter if private.

in your case:

public class ServiceImpl{

   @Value("${page-cache.starting}")
   private Boolean serviceEnabled;

   // can be getServiceEnabled
   public Boolean isServiceEnabled() { 
    return this.serviceEnabled;
   }

   @EventListener(
        value = ApplicationReadyEvent.class,
        condition = "@serviceImpl.serviceEnabled")
   public void updateCacheAfterStartup() {
    log.info("Info add starting...");
   someService.getInfo();
}