Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring bean is created, but is null when Autowired

Tags:

java

spring

I am trying to inject an object to a class. However, the field is always null. I tried @Autowired and @Resource annotations. I am not creating the object with new operator anywhere. The constructor of Foo is called properly.

The minimal example of this problem:

Foo class

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

Bar class

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

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

Entry point

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>

Why is foo field of Bar class always null? How can I fix this?

like image 607
RK1 Avatar asked Oct 31 '22 08:10

RK1


1 Answers

As @Mick pointed out, field injection necessarily takes place after the constructor is finished (there's no other way for Spring to see the instance and manipulate it). Modify your class to use constructor injection, and you'll both make your dependencies more explicit (and thus easier to test, for example) and eliminate what's essentially a race condition:

public class Bar {
    private Foo foo;

    @Autowired
    public Bar(Foo foo) {
        this.foo = foo;
        foo.func();
    }
}
like image 58
chrylis -cautiouslyoptimistic- Avatar answered Nov 15 '22 04:11

chrylis -cautiouslyoptimistic-