为什么@Autowired(required = false)不适用于@Configuration bean?

时间:2014-08-06 09:54:52

标签: java spring configuration autowired

让我们举个例子说明:

拥有这个bean:

public class Foo {
    private String name;

    Foo(String name) {
        this.name = name;
    }

    public String getName() {
        return this.name;
    }
}

这项服务:

public class FooService {
    private Foo foo;

    FooService(Foo foo) {
        this.foo = foo;
    }

    Foo getFoo() {
        return this.foo;
    }
}

给出以下Spring配置:

@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);
    }
}

为了完整起见,这是一个简单的单元测试:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {SpringContext.class})
public class SpringAppTests {
    @Autowired
    private FooService fooService;

    @Test
    public void testGetName() {
        Assert.assertEquals("foo", fooService.getFoo().getName());
    }
}

然后加载上下文将抛出NoSuchBeanDefinitionException(Foo)。

在这个例子中,任何人都可以看到任何错误/缺失,或者为我提供理由吗?

谢谢!基督教

3 个答案:

答案 0 :(得分:6)

除了其他答案:

问题是spring在注入参数时不会考虑required=false。见ConstructorResolver

return this.beanFactory.resolveDependency(
        new DependencyDescriptor(param, true), beanName, autowiredBeanNames, typeConverter);

第二个参数总是true

public DependencyDescriptor(MethodParameter methodParameter, boolean required)

编辑: Spring使用ConstructorResolver

  • “真正的”构造注入

    @Autowired(required=false) // required=false WILL NOT WORK
    public FooService(Foo foo){
        ...
    }
    
  • 工厂方法

    @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);
    }
    

因此,在这两种情况下都会忽略required属性。

答案 1 :(得分:3)

您的语法错误。 @Autowired(required = false)需要与Foo相关联。

例如:

@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);
    }
}

答案 2 :(得分:2)

尝试

@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);
    }
}