Reputation: 199
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
Upvotes: 8
Views: 17245
Reputation: 3912
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);
}
Upvotes: 4
Reputation: 51463
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.
Upvotes: 10
Reputation: 4121
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);
}
}
Upvotes: 4
Reputation: 120851
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);
}
}
Upvotes: 2