Spring重写bean配置设置其"Primary"

voi*_*oid 8 java spring spring-bean

使用Spring 3.XX我有2个使用@Primary注释的服务,我创建了另一个配置类,我想使用其中一个服务的"自定义"版本.

出于某种原因,我在调试配置类时忽略了我看到它获得了正确的依赖关系,但是当我想使用它时,它设置了错误的依赖关系.

我发现使用代码更容易解​​释,这是一个例子:

界面Foo:

public interface Foo {
    String getMessage();
}
Run Code Online (Sandbox Code Playgroud)

使用硬编码的默认消息的主要实现:

@Primary
@Service("FooImpl")
public class FooImpl implements Foo {

    private String message = "fooDefaultMessage";

    @Override
    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}
Run Code Online (Sandbox Code Playgroud)

栏界面:

public interface Bar {

    void doBar();
}
Run Code Online (Sandbox Code Playgroud)

栏默认实施:

@Primary
@Service("BarImpl")
public class BarImpl implements Bar {

    private Foo foo;

    @Override
    public void doBar() {
        System.out.println(foo.getMessage());
    }

    public Foo getFoo() {
        return foo;
    }

    @Autowired
    public void setFoo(Foo foo) {
        this.foo = foo;
    }
}
Run Code Online (Sandbox Code Playgroud)

到目前为止一切顺利,如果我想要注入一个酒吧,我会按预期得到一切.事情是我有一个配置如下:

@Configuration
public class BeanConfiguration {

    @Bean
    @Qualifier("readOnlyFoo")
    Foo readOnlyFoo() {
        FooImpl foo = new FooImpl();
        foo.setMessage("a read only message");
        return foo;
    }

    @Bean
    @Qualifier("readOnlyBar")
    Bar readOnlyBar() {
        BarImpl bar = new BarImpl();
        bar.setFoo(readOnlyFoo());
        return bar;
    }
}
Run Code Online (Sandbox Code Playgroud)

当我想注入一个readOnlyBar时,我得到了默认的Foo而不是这里设置的那个.

private Bar readOnlyBar;

@Autowired
@Qualifier("readOnlyBar")
public void setReadOnlyBar(Bar readOnlyBar) {
    this.readOnlyBar = readOnlyBar;
}

...
readOnlyBar.doBar();
Run Code Online (Sandbox Code Playgroud)

Foo bean的"fooDefaultMessage".这是为什么?如何确保Spring使用我在@Configuration上设置的Bean?

提前致谢,

编辑:请注意,如果不是在@Configuration类中调用readOnly()方法,而是传递@Qualified参数,则会发生同样的情况.即:

@Configuration
public class BeanConfiguration {

    @Bean
    @Qualifier("readOnlyFoo")
    Foo readOnlyFoo() {
        FooImpl foo = new FooImpl();
        foo.setMessage("a read only message");
        return foo;
    }

    @Bean
    @Qualifier("readOnlyBar")
    Bar readOnlyBar(@Qualifier("readOnlyFoo") Foo readOnlyFoo) {
        BarImpl bar = new BarImpl();
        bar.setFoo(readOnlyFoo);
        return bar;
    }
}
Run Code Online (Sandbox Code Playgroud)

相反,如果我尝试使用构造函数依赖注入,一切都按照我想要/期望的方式工作但不幸的是我无法使用它.

yas*_*nth 2

您不能像您那样使用@Autowired实例变量并在方法中设置它。@Beanspring 生命周期的一部分是这样的

扫描 Bean 定义 => 创建 Bean 实例 => 调用后处理器 => .....

在你的例子中,

@Bean
@Qualifier("readOnlyBar")
Bar readOnlyBar() {
    BarImpl bar = new BarImpl();
    bar.setFoo(readOnlyFoo());
    return bar;
}
Run Code Online (Sandbox Code Playgroud)

readOnlyBarbean 被创建,并且因为readOnlyFoo()是从该方法中调用的,所以readOnlyFoobean 也被实例化。到目前为止,它的实例变量已经存在readOnlyBarreadOnlyFoo一旦 bean 被实例化,AutowiredAnnotationBeanPostProcessor就会调用 来扫描 bean 的类(BarImpl在本例中)以查找@Autowired实例变量或方法上的任何注释。@Autowired它找到它们并尝试使用字段注入或 setter 注入(无论注释存在的位置)将 bean 注入到相应的变量中。在这种情况下,由于我们有@Autowiredsetter并且没有指定注释@Qualifier,所以spring注入的@Primarybean就是defaultFooMessagebean。

AFAIK,在 spring 中没有直接的方法来配置@Bean优先于自动装配的方法。

使用方法实例化所有 bean@Bean将解决该问题。