Spring bean已创建,但在Autowired时为空。

5

我正在尝试向一个类中注入一个对象,但是这个字段总是为空。我尝试了@Autowired@Resource注释。我没有在任何地方使用new操作符创建对象。Foo的构造函数被正确调用。

这个问题的最小示例:

Foo类

package foo.bar;
public class Foo {
    Foo(){
        System.out.println("Foo constructor");
    }
    public void func() {
        System.out.println("func()");
    }
}

Bar类

package foo.bar;
public class Bar {
    @Autowired
    private Foo foo;

    public Bar() {
        foo.func();
    }
}

入口点

package foo.bar;
public class HelloApp {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
    }
}

spring-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    <context:component-scan base-package="foo.bar"/>
    <bean id = "foo" class="foo.bar.Foo" />
    <bean id = "bar" class="foo.bar.Bar" />
</beans>

为什么 Bar 类的 foo 字段总是 null?我该怎么解决这个问题?

3
构造方法在字段自动装配之前被调用。因此,在Bar构造函数中调用foo.func();将导致空指针异常。你可以创建一个方法来调用foo.func(); 并使用 @PostConstruct 进行注释,以避免这种情况发生。 - Michael W
1个回答

2
正如 @Mick 指出的那样,字段注入必须在构造函数完成后才能进行(这是 Spring 看到实例并操纵它的唯一方式)。修改你的类以使用构造函数注入,你不仅可以使依赖关系更加明确(例如更容易进行测试),还可以消除本质上的竞态条件:
public class Bar {
    private Foo foo;

    @Autowired
    public Bar(Foo foo) {
        this.foo = foo;
        foo.func();
    }
}

谢谢,那很好用。我只是认为在Spring中整个初始化过程(或应该)总是在xml文件中声明bean时执行。现在我必须在某个地方创建Foo对象并将其传递给构造函数。 - RK1
Spring知道如何自动装配构造函数。你根本不需要更改XML bean定义。(如果您想要在XML中显式提供构造函数参数,可以这样做,但只要bean是明确的,Spring就可以为您解决它们。) - chrylis -cautiouslyoptimistic-
是的,我不需要做任何改变。我只是认为在使用Spring时不需要在任何地方实例化beans。 - RK1
1
@RK1 通常情况下,你不需要手动实例化 bean,但是必须有 某个东西 来实例化它们,否则它们从哪里来呢? - chrylis -cautiouslyoptimistic-
如果 Bar 不是一个 bean 呢?我们仍然必须显式地创建一个 Foo 对象并将其传递给 Bar 构造函数,因此 @Autowired 就变得无用了,不是吗? - mangusta
此外,自动装配发生的时间有多快?例如,我已经创建了一个类A的实例,其中包含自动装配字段,并检查该字段是否为空,但它仍然为空,即使A的构造函数已经执行完毕。 - mangusta

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接