Search code examples
javaspring-bootspring-el

Reference @ConstructorBinding's in SpEL not works?


I have a final config-class like this:

@Value // <- lombok-annotation
@ConstructorBinding
@ConfigurationProperties("my-app.conf")
public class MyProperties {
  Duration reloadPeriod;
}

And I want to use the reloadPeriod in a @Scheduled field like this:

@Service
public class MyService {

   @Scheduled(fixedDelayString = "#{myProperties.reloadPeriod}")
   public void doSomeRecurrentStuff() {
      // some work
   }
}

But this setup will always fail with this error:

Caused by: org.springframework.expression.spel.SpelEvaluationException: EL1008E: Property or field 'myProperties' cannot be found on object of type 'org.springframework.beans.factory.config.BeanExpressionContext' - maybe not public or not valid?

When I add an "intermediate bean" like this:

@Configuration
public class MyConfigClass {

   @Bean("reloadPeriod")
   Duration reloadPeriod(MyProperties props) {
      return props.getReloadPeriod();
   }
}

then I can reference it without any problems like this: @Scheduled(fixedDelayString = "#{reloadPeriod}")

tldr;

How can I access "like beans" created by @ConstructorBinding via SpEL?


Solution

  • You can use beanFactory to get the configuration properties bean by its type.

    @Scheduled(fixedDelayString = 
                "#{beanFactory.getBean(T(com.package.MyProperties)).reloadPeriod}")
    public void doSomeRecurrentStuff() {
        // ...
    }
    

    Alternatively, implement SchedulingConfigurer to programmatically set up scheduled tasks.

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.scheduling.annotation.SchedulingConfigurer;
    import org.springframework.scheduling.config.ScheduledTaskRegistrar;
    
    @Configuration
    public class SchedulerConfig implements SchedulingConfigurer {
        @Autowired
        private MyProperties myProperties;
        
        void doSomeRecurrentStuff() {
            // some work
        }
    
        @Override
        public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
            taskRegistrar.addFixedDelayTask(this::doSomeRecurrentStuff, 
                  myProperties.getReloadPeriod());
        }
    }