Why @Autowired(required=false) do not work on @Configuration beans?
Solution 1
In addition to the other answers:
The problem is that spring does not take the required=false
into account when injecting parameters. See ConstructorResolver
return this.beanFactory.resolveDependency(
new DependencyDescriptor(param, true), beanName, autowiredBeanNames, typeConverter);
The second argument is always true
:
public DependencyDescriptor(MethodParameter methodParameter, boolean required)
EDIT: Spring uses the ConstructorResolver
for
-
"real" constuctor injection
@Autowired(required=false) // required=false WILL NOT WORK public FooService(Foo foo){ ... }
-
factory methods
@Bean @Autowired(required=false) // required=false WILL NOT WORK FooService fooService(Foo foo) { if (foo == null) { return new FooService(new Foo("foo")); } return new FooService(foo); }
Thus in both cases the required
attribute is ignored.
Solution 2
You have your syntax wrong. The @Autowired(required = false)
would need to be relating to the Foo
.
For example:
@Configuration
public class SpringContext {
@Autowired(required = false)
private Foo foo;
@Bean
FooService fooService() {
if (foo == null) {
return new FooService(new Foo("foo"));
}
return new FooService(foo);
}
}
Solution 3
Try
@Configuration
public class SpringContext {
// @Bean
// Foo foo() {
// return new Foo("foo");
// }
@Autowired(required = false)
Foo foo;
@Bean
FooService fooService() {
if (this.foo == null) {
return new FooService(new Foo("foo"));
}
return new FooService(this.foo);
}
}
Solution 4
required=false
does work on @Configuration
beans, however, the @Autowired
annotation should be placed along with the constructor argument. This is the correct syntax:
@Bean
Test1 test1(@Autowired(required = false) Test2 test2){
return new Test1(test2);
}
Christian Sisti
(your about me is currently blank) click here to edit
Updated on June 30, 2022Comments
-
Christian Sisti almost 2 years
Let explain with an example:
Having this bean:
public class Foo { private String name; Foo(String name) { this.name = name; } public String getName() { return this.name; } }
And this service:
public class FooService { private Foo foo; FooService(Foo foo) { this.foo = foo; } Foo getFoo() { return this.foo; } }
Given the following Spring configuration:
@Configuration public class SpringContext { // @Bean // Foo foo() { // return new Foo("foo"); // } @Bean @Autowired(required = false) FooService fooService(Foo foo) { if (foo == null) { return new FooService(new Foo("foo")); } return new FooService(foo); } }
For completeness here is a simple unit test:
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = {SpringContext.class}) public class SpringAppTests { @Autowired private FooService fooService; @Test public void testGetName() { Assert.assertEquals("foo", fooService.getFoo().getName()); } }
Then loading the context will throw a NoSuchBeanDefinitionException (Foo).
Can anyone see anything wrong/missing on this example, or provide me a reason for that?
Thank you! Christian