Reputation: 405
I have a class with two final fields of the same type, and I need to make second field injected with null
if property props.enabled
in application.yml
is false
. However, if it's false
Spring Boot injects both fields with the same bean instance.
How to forbid Spring Boot injecting both fields of the same type with the same bean instance?
@AllArgsConstructor
public class MySettings {
private int val;
}
My configuration class
@Configuration
public class MySpringConfig {
@Bean
public MySettings settingsA() {
return new MySettings(1);
}
@Bean
@ConditionalOnProperty(prefix = "props", name = "enabled")
public MySettings settingsB() {
return new MySettings(2);
}
}
And this is my class
@Component
@RequiredArgsConstructor
public class MyClass {
private final MySettings settingsA; // MySettings(1)
private final MySettings settingsB; // also MySettings(1) but must be null if props.enabled=false
@Value("${props.enabled}")
private boolean enabled;
...
}
This is part of the real project, so I have very little space to deviate from
UPDATE
I came up with solution of constructor injection but the code starts to look ugly
@Component
public class MyClass {
private final MySettings settingsA;
private final MySettings settingsB;
private boolean enabled;
public MyClass(MySettings settingsA,
@Nullable @Qualifier("settingsB") MySettings settingsB,
@Value("${props.enabled}") boolean enabled) {
this.settingsA = settingsA;
this.settingsB = settingsB;
this.enabled = enabled;
}
...
Upvotes: 1
Views: 400
Reputation: 17460
You need a qualifier to tell Spring which bean to inject:
@Configuration
public class MySpringConfig {
@Bean(name = "SettingsA")
public MySettings settingsA() {
return new MySettings(1);
}
@Bean(name = "SettingsB")
@ConditionalOnProperty(prefix = "props", name = "enabled")
public MySettings settingsB() {
return new MySettings(2);
}
}
And now in MyClass
:
@Component
public class MyClass {
private final MySettings settingsA;
private final MySettings settingsB;
@Value("${props.enabled}")
private boolean enabled;
public MyClass(@Qualifier("SettingsA") MySettings settingsA, @Qualifier("SettingsB") MySettings settingsB) {
this.settingsA = settingsA;
this.settingsB = settingsB;
}
...
}
However, since one of those Beans might not be available I believe you need to not include it in the constructor injection otherwise you will get an error. In that case you need to do the following:
@Component
public class MyClass {
@Qualifier("SettingsA")
@Autowired
private MySettings settingsA;
@Qualifier("SettingsB")
@Autowired(required = false)
private MySettings settingsB;
@Value("${props.enabled}")
private boolean enabled;
...
}
Upvotes: 1