Semi-recently (“semi” because procrastination kept me from writing, so it’s more like two months ago, but blog posts have to start with “recently” when you try to explain yourself why you are writing what you are writing – but I’m getting sidetracked here, so let’s move on) I was wondering whether Java classes annotated with Spring’s @ConfigurationProperty should be declared as a bean, e.g. with @Component. I didn’t find a definitive answer, but I found three ways on how to do it – typical Spring, I guess.
Here’s a quick setup:
My configuration class.
package com.thecodeslinger.configpropsdemo;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
@Data
@ConfigurationProperties(prefix = "demo")
public class Configuration {
private String elegy;
}
My main application:
package com.thecodeslinger.configpropsdemo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import javax.annotation.PostConstruct;
@SpringBootApplication
public class ConfigPropsDemoApplication {
@Autowired
private Configuration configuration;
@PostConstruct
public void postConstruct() {
System.out.println(configuration.getElegy());
}
public static void main(String[] args) {
SpringApplication.run(ConfigPropsDemoApplication.class, args);
}
}
And finally, my properties file:
demo.elegy=R.I.P. Kobe
It’s not an elegant setup, but that’s not the point. It does the job for now.
If you run the application in this state, Spring will greet you with an error message.
APPLICATION FAILED TO START Description: Field configuration in com.thecodeslinger.configpropsdemo.ConfigPropsDemoApplication required a bean of type 'com.thecodeslinger.configpropsdemo.Configuration' that could not be found. The injection point has the following annotations: - @org.springframework.beans.factory.annotation.Autowired(required=true) Action: Consider defining a bean of type 'com.thecodeslinger.configpropsdemo.Configuration' in your configuration.
It obviously cannot find the configuration bean.
Option #1: Slap @Component to it.
package com.thecodeslinger.configpropsdemo;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Data
@Component
@ConfigurationProperties(prefix = "demo")
public class Configuration {
private String elegy;
}
Option #2: Use the @EnableConfigurationProperties annotation.
import org.springframework.boot.context.properties.EnableConfigurationProperties;
@SpringBootApplication
@EnableConfigurationProperties(Configuration.class)
public class ConfigPropsDemoApplication {
Option #3: Use @ConfigurationPropertiesScan to explicitly name the packages to scan for.
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
@SpringBootApplication
@ConfigurationPropertiesScan({"com.thecodeslinger.configpropsdemo"})
public class ConfigPropsDemoApplication {
All three options achieve what you’re aiming for, a running application.
:: Spring Boot :: (v2.2.4.RELEASE) 2020-02-03 19:57:43.562 INFO 4612 --- [ main] c.t.c.ConfigPropsDemoApplication : Starting ConfigPropsDemoApplication on DESKTOP-C0O3OKC with PID 4612 (D:\OneDrive\Code\Java\config-props-demo\target\classes started by lober in D:\OneDrive\Code\Java\config-props-demo) 2020-02-03 19:57:43.562 INFO 4612 --- [ main] c.t.c.ConfigPropsDemoApplication : No active profile set, falling back to default profiles: default R.I.P. Kobe 2020-02-03 19:57:43.921 INFO 4612 --- [ main] c.t.c.ConfigPropsDemoApplication : Started ConfigPropsDemoApplication in 0.573 seconds (JVM running for 1.083)
So, is there any benefit of one over the other? The Spring documentation has the following to say:
Sometimes, classes annotated with
@ConfigurationProperties
might not be suitable for scanning, for example, if you’re developing your own auto-configuration or you want to enable them conditionally. In these cases, specify the list of types to process using the@EnableConfigurationProperties
annotation. This can be done on any@Configuration
class, as shown in the following example:
I’m not using a @Configuration class in my example, but if you were, you could leverage that to load your configuration classes based on @Profile annotations. Although @Component works too, it’s not mentioned in that part of the Spring documentation (“Type-safe Configuration Properties”).
For myself, I might go with @EnableConfigurationProperties and if it makes sense, even have dedicated @Configuration classes linked to @Profile. For little samples like this one it’s obviously overkill. In a remotely useful application, the additional overhead may be worth it for structural and documentational reasons.