So, I have the following application:
@SpringBootApplication
public class AutonullApplication {
public static void main(String[] args) {
SpringApplication.run(AutonullApplication.class, args);
}
@Bean
First first() {
return null;
}
public class First {
}
@Service
public class Second {
private final First first;
public Second(First first) {
this.first = first;
}
@PostConstruct
public void print() {
System.out.println("First = " + first);
}
}
}
which tries to inject a bean of type First
into a service of type Second
. But the bean has a value of null
. This code works fine in Spring Boot 1.5.10 (and so Spring 4), but fails in Spring Boot 2.0 (and Spring 5):
Description:
Parameter 1 of constructor in eu.plumbr.autonull.AutonullApplication$Second required a bean of type 'eu.plumbr.autonull.AutonullApplication$First' that could not be found.
Is anybody aware of any mention of such change in the official documentation?
And finally, the bean is destroyed when the spring container is closed. Therefore, if we want to execute some code on the bean instantiation and just after closing the spring container, then we can write that code inside the custom init() method and the destroy() method.
In Spring, you can uses this special <null /> tag to pass a “null” value into constructor argument or property.
Spring bean life cycle can be controlled in the following ways. Instantiation by using: InitializingBean callback interface. Custom init() method from the bean configuration file.
The identifier of the parameter matches the name of one of the beans from the context (which is the same as the name of the method annotated with @Bean that returns its value). In this case, Spring chooses that bean for which the name is the same as the parameter.
Yes, this is a breaking change in Spring Framework 5. Arguably, such setup is weird and we wanted to tighten those rules a little bit.
If you request to inject First
and you provide null
, then it's more consistent to consider that bean isn't provided. You can then query the context for the presence of First
. @spencergibb already explained how you can use Optional
, or you can use ObjectProvider<First>
as an injection point:
@Service
public class Second {
private final First first;
public Second(ObjectProvider<First> first) {
this.first = first.getIfAvailable(); // return null
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With