@Autowired注入的属性在构造函数中调用时为null。

huangapple go评论94阅读模式
英文:

Autowired property is null when I call it in constructor

问题

以下是翻译好的部分:

我有一个演示类`FooComponent`,它在`FooService`中进行自动装配并在其构造函数中访问

FooComponent.class

    @Component("fooComponent")
    public class FooComponent {
        public String format() {
            return "foo";
        }
    }

FooService.class

    @Component
    public class FooService {
    
        @Autowired
        private FooComponent fooComponent;
    
        public FooService() {
            System.out.println("在foo服务构造函数中=" + this.fooComponent);
        }
    
        String doTatti() {
            return fooComponent.format();
        }
    }


MainApplication

    @SpringBootApplication
    public class InterviewApplication {
    
        public static void main(String[] args) {
            ApplicationContext ctx = SpringApplication.run(InterviewApplication.class, args);
            System.out.println(ctx.getBean(FooService.class).doTatti());
        }
    }

[教程][1]作者说在上面的示例中Spring在创建FooService时查找并注入fooFormatter。”在我的情况下fooFormatter 是 fooComponent

但每次在构造函数中我的自动装配属性都为null我认为这是因为`FoOService`尚未完全初始化这个假设是否正确

如果我的假设是正确的那么为什么下面的代码有效

    @Autowired
    public FooService(FooComponent fooComponent) {
            System.out.println("在foo服务构造函数中=" + fooComponent);
    }

我知道这是一个非常基础和愚蠢的问题但我需要帮助理解它

# 更新
最后一个问题是否有一种方法可以在`MainApplication`中进行`Autowire`我的`FooService`实例而不是从`ApplicationContext`中获取它

提前感谢您

  [1]: https://www.baeldung.com/spring-autowire
英文:

I have a demo class FooComponent which is autowired in FooService and accessed in its constructor.

FooComponent.class:

@Component("fooComponent")
public class FooComponent {
public String format() {
return "foo";
}
}

FooService.class:

@Component
public class FooService {
@Autowired
private FooComponent fooComponent;
public FooService() {
System.out.println("in foo service const=" + this.fooComponent);
}
String doTatti() {
return fooComponent.format();
}
}

MainApplication:

@SpringBootApplication
public class InterviewApplication {
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(InterviewApplication.class, args);
System.out.println(ctx.getBean(FooService.class).doTatti());
}
}

In this tutorial, author says In the above example, Spring looks for and injects fooFormatter when FooService is created. In my case, fooFormatter is fooComponent.

But everytime, in the constructor my autowired property is null. My assumption is that it is because FoOService has not completely initialized? Is this correct?

If my assumption is correct, then why does below code work?

@Autowired
public FooService(FooComponent fooComponent) {
System.out.println("in foo service const=" + fooComponent);
}

I know this is very basic and stupid question, but I need help in understanding it.

UPDATE:

One last query, is there a way to Autowire my FooService instance in MainApplication, instead of getting it from ApplicationContext?

Thank you in advance.

答案1

得分: 1

在Spring中,bean在其属性被注入之前被实例化。即:

  1. 首先实例化bean
  2. 注入属性
    这是因为Spring使用实例化的bean的setter方法来注入属性。

这就是你遇到NullPointerException的原因。

首选且推荐的选项是使用构造函数注入,而不是属性或setter注入。另外,解决这个问题的一种方式是像你所做的那样创建带有参数的构造函数。

你可以在这里找到完整的解释:
https://dzone.com/articles/spring-accessing-injected

编辑:
Bean应该由容器进行管理。如果我们想使用其中之一,我们应该依赖于依赖注入,而不是直接调用ApplicationContext.getBean()。

参考这篇帖子:https://stackoverflow.com/questions/812415/why-is-springs-applicationcontext-getbean-considered-bad

英文:

In Spring, a bean is instantiated before its properties are injected. That is:

  1. Instantiate the bean first
  2. Inject the properties
    This is because spring uses setter methods of the instantiated bean in order to inject properties.

This is the reason you are getting NullPointerException.

Preferable and recommended option is to use constructor injection, not a property or setter injection. In additional, one of the ways to resolve this is to create constructor with parameter as you did.

The whole explanation you can check here:
https://dzone.com/articles/spring-accessing-injected

EDIT:
Beans should be managed by the container. If we want to use one of them, we should rely on dependency injection rather than a direct call to ApplicationContext.getBean().

See this post: https://stackoverflow.com/questions/812415/why-is-springs-applicationcontext-getbean-considered-bad

答案2

得分: 0

你需要使用构造函数注入而不是setter注入。
setter注入的缺点之一是它不能确保依赖注入。你无法保证某个依赖项是否被注入,这意味着你可能会拥有一个具有不完整依赖项的对象。另一方面,构造函数注入不允许你构造一个对象,直到你的依赖项准备好为止。

英文:

You need to use constructor injection instead of setter injection.
one of the drawbacks of setter injection is that it does not ensures dependency Injection. You can not guarantee that certain dependency is injected or not, which means you may have an object with incomplete dependency. On the other hand, constructor Injection does not allow you to construct an object until your dependencies are ready.

答案3

得分: 0

  1. 对于您的第一个问题,您是正确的。此外,当您需要在构造函数中使用对象时,您必须使用构造函数注入,而不是在属性中使用 @Autowired 进行属性注入;

  2. 对于您的第二个问题,您可以在主类中使用 @Autowired 属性,但通常在这种情况下,最好在实现 commandLineRunner 接口的重写方法中执行逻辑,如下所示:

     @Autowired
    private FooService foo;
    public static void main(String[] args) {
    SpringApplication.run(InterviewApplication.class, args);
    }
    @Override
    public void run(String... args) throws Exception {
    foo.doTatti();  
    ...
    }
    
英文:
  1. for your first question, u r right. Also when u need an object in the constructor you have to use the constructor injection and not property injection with @autowired;

  2. for your second one, u can use the @Autowired prop in the main, but usually in this case is better to do your logic in the override of the commandLineRunner interface as follow :

    @Autowired
    private FooService foo;
    public static void main(String[] args) {
    SpringApplication.run(InterviewApplication.class, args);
    }
    @Override
    public void run(String... args) throws Exception {
    foo.doTatti();  
    ...
    }
    

huangapple
  • 本文由 发表于 2020年4月4日 22:34:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/61029655.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定