Перейти к основному содержимому

Spring @Autowired Field Null — распространенные причины и решения

· 3 мин. чтения

1. Обзор

В этом руководстве мы рассмотрим распространенные ошибки, которые приводят к исключению NullPointerException в поле Autowired . Мы также объясним, как решить проблему.

2. Постановка задачи

Во-первых, давайте определим компонент Spring с пустым методом doWork :

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

Затем давайте определим наш класс обслуживания. Мы будем использовать возможности Spring для внедрения bean-компонента MyComponent внутри нашего сервиса, чтобы мы могли вызывать метод doWork внутри метода сервиса:

public class MyService {

@Autowired
MyComponent myComponent;

public String serve() {
myComponent.doWork();
return "success";
}
}

Теперь давайте добавим контроллер, который будет создавать экземпляр службы и вызывать метод serve :

@Controller
public class MyController {

public String control() {
MyService userService = new MyService();
return userService.serve();
}
}

На первый взгляд наш код может выглядеть совершенно нормально. Однако после запуска приложения вызов метода управления нашего контроллера приведет к следующему исключению:

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

Что здесь случилось? Когда мы вызвали конструктор MyService в нашем контроллере, мы создали объект, который не управляется Spring. Не зная о существовании этого объекта MyService , Spring не может внедрить в него bean-компонент MyComponent . Таким образом, экземпляр MyComponent внутри созданного нами объекта MyService останется нулевым, вызывая исключение NullPointerException , которое мы получаем, когда пытаемся вызвать метод для этого объекта.

3. Решение

Чтобы решить эту проблему, мы должны сделать экземпляр MyService , используемый в нашем контроллере, компонентом, управляемым Spring.

Во-первых, давайте скажем Spring сгенерировать Bean для нашего класса MyService . У нас есть различные возможности для этого. Самый простой — украсить класс MyService аннотацией @Component или любой из ее производных. Например, мы могли бы сделать следующее:

@Service
public class MyService {

@Autowired
MyComponent myComponent;

public String serve() {
myComponent.doWork();
return "success";
}
}

Другой альтернативой для достижения той же цели является добавление метода @Bean в файл @Configuration :

@Configuration
public class MyServiceConfiguration {

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

Однако превращения класса MyService в bean-компонент, управляемый Spring, недостаточно. Теперь мы должны автоматически связать его внутри нашего контроллера, вместо того, чтобы вызывать для него new . Посмотрим, как выглядит исправленная версия контроллера:

@Controller
public class MyController {

@Autowired
MyService myService;

public String control() {
return myService.serve();
}
}

Теперь вызов метода управления вернет результат метода serve , как и ожидалось.

4. Вывод

В этой статье мы увидели очень распространенную ошибку, которая может вызвать исключение NullPointerException , когда мы непреднамеренно смешиваем внедрение Spring с объектами, которые мы создаем, вызывая их конструкторы. Мы исправили проблему, избежав этой ответственности mic-mac, и превратили объект, который мы использовали для управления собой, в компонент, управляемый Spring.

Как всегда, код доступен на GitHub .