Spring @Autowired Field Null – Common Causes and Solutions – Spring @Autowired Field Null – 常见原因和解决方案

最后修改: 2022年 2月 17日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this tutorial, we’ll see common errors that lead to a NullPointerException on an Autowired field. We’ll also explain how to fix the problem.

在本教程中,我们将看到导致NullPointerExceptionAutowired字段的常见错误。我们还将解释如何解决这个问题。

2. Presentation of the Problem

2.问题的提出

First, let’s define a Spring component with an empty doWork method:

首先,让我们定义一个带有空doWork方法的Spring组件。

@Component
public class MyComponent {
    public void doWork() {}
}

Then, let’s define our service class. We’ll use Spring capacities to inject a MyComponent bean inside our service so that we can call the doWork method inside the service method:

然后,让我们来定义我们的服务类。我们将使用Spring能力在我们的服务中注入一个MyComponent Bean,这样我们就可以在服务方法中调用doWork方法。

public class MyService {
    
    @Autowired
    MyComponent myComponent;
    
    public String serve() {
        myComponent.doWork();
        return "success";
    }
}

Now, let’s add a controller which will instantiate a service and call the serve method:

现在,让我们添加一个控制器,它将实例化一个服务并调用serve方法。

@Controller
public class MyController {
    
    public String control() {
        MyService userService = new MyService();
        return userService.serve();
    }
}

At first glance, our code might look perfectly fine. However, after running the application, calling the control method of our controller will lead to the following exception:

乍一看,我们的代码可能看起来非常好。然而,在运行应用程序后,调用我们控制器的控制方法将导致以下异常。

java.lang.NullPointerException: null
  at com.baeldung.autowiring.service.MyService.serve(MyService.java:14)
  at com.baeldung.autowiring.controller.MyController.control(MyController.java:12)

What happened here? When we called the MyService constructor in our controller, we created an object that is not managed by Spring. Having no clue of the existence of this MyService object, Spring is not able to inject a MyComponent bean inside it. Thus, the MyComponent instance inside the MyService object we created will remain null, causing the NullPointerException we get when we try to call a method on this object.

这里发生了什么?当我们在控制器中调用MyService构造函数时,我们创建了一个不被Spring管理的对象。由于不知道这个MyService对象的存在,Spring无法在其中注入一个MyComponentbean。因此,我们创建的MyService对象中的MyComponent实例将保持为空,导致我们在尝试调用该对象的方法时得到NullPointerException/a>。

3. Solution

3.解决办法

To solve this problem, we have to make the MyService instance used in our controller a Spring-managed Bean.

为了解决这个问题,我们必须让控制器中使用的MyService实例成为Spring管理的Bean。

First, let’s tell Spring to generate a Bean for our MyService class. We have various possibilities to achieve this. The easiest one is to decorate the MyService class with the @Component annotation or any of its derivatives. For example, we could do the following:

首先,让我们告诉Spring为我们的MyService类生成一个Bean。我们有各种可能性来实现这个目标。最简单的是用@Component注解或其任何衍生物来装饰MyService类。例如,我们可以这样做。

@Service
public class MyService {
    
    @Autowired
    MyComponent myComponent;
    
    public String serve() {
        myComponent.doWork();
        return "success";
    }
}

Another alternative to reach the same goal is to add a @Bean method in a @Configuration file:

另一个达到相同目标的方法是在@Configuration文件中添加一个@Bean方法。

@Configuration
public class MyServiceConfiguration {

    @Bean
    MyService myService() {
        return new MyService();
    }
}

However, turning MyService class into a Spring-managed bean is not enough. Now, we have to autowire it inside our controller, instead of calling new on it. Let’s see how the fixed version of the controller looks:

然而,把MyService类变成一个Spring管理的bean是不够的。现在,我们必须在我们的控制器中自动连接它,而不是对它调用new 。让我们看看控制器的固定版本是什么样子的。

@Controller
public class MyController {
    
    @Autowired
    MyService myService;
    
    public String control() {
        return myService.serve();
    }
}

Now, calling the control method will return the result of the serve method as expected.

现在,调用控制方法将按照预期返回serve方法的结果。

4. Conclusion

4.总结

In this article, we have seen a very common error that would cause a NullPointerException when we unintentionally mix Spring injection with objects we create by calling their constructors. We fixed the problem by avoiding this responsibility mic-mac and turned the object we used to managed ourselves into a Spring-managed Bean.

在这篇文章中,我们看到了一个非常常见的错误,当我们无意间将Spring注入与我们通过调用构造函数创建的对象混合在一起时,会导致NullPointerException。我们通过避免这种责任mic-mac来解决这个问题,并将我们用来管理自己的对象变成了一个Spring管理的Bean。

As always the code is available over on GitHub.

像往常一样,代码可在GitHub上获得。