1. 概述
在本教程中,我們將探討導致在 Autowired 字段上出現 NullPointerException 的常見錯誤。我們還將解釋如何解決這個問題。
2. 問題呈現
首先,讓我們定義一個 Spring 組件,該組件具有空 doWork 方法:
@Component
public class MyComponent {
public void doWork() {}
}然後,我們定義我們的服務類。我們將使用 Spring 的依賴注入機制,將 MyComponent Bean 注入到我們的服務中,以便在服務方法中調用 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.baeldung.autowiring.service.MyService.serve(MyService.java:14)
at com.baeldung.autowiring.controller.MyController.control(MyController.java:12)這裏發生了什麼?當我們控制器中調用 MyService 構造函數時,我們創建了一個未受 Spring 管理的對象。 Spring 不知道 MyService 對象的存在,因此無法在其內部注入 MyComponent Bean。 因此,在由 MyService 對象創建的 MyComponent 實例將保持為 null,從而導致我們在嘗試調用該對象的方法時出現 NullPointerException。
3. 解決方案
為了解決此問題,我們需要將控制器中使用的 <em MyService</em>> 實例配置為 Spring 管理的 Bean。
首先,我們需要告訴 Spring 生成一個 Bean 用於我們的 <em MyService</em>> 類。 實現此目的的方法有很多種。 最簡單的方法是使用 @Component 註解(及其任何派生類)裝飾 <em MyService</em>> 類。 例如,我們可以執行以下操作:
@Service
public class MyService {
@Autowired
MyComponent myComponent;
public String serve() {
myComponent.doWork();
return "success";
}
}另一個實現相同目標的替代方案是在一個 @Configuration/” 文件中添加一個 @Bean/” 方法:
@Configuration
public class MyServiceConfiguration {
@Bean
MyService myService() {
return new MyService();
}
}然而,將 MyService 類轉變為 Spring 管理的 Bean 還不夠。現在,我們需要在控制器中自動注入它,而不是使用 new 創建它。下面是修復後的控制器的樣子:
@Controller
public class MyController {
@Autowired
MyService myService;
public String control() {
return myService.serve();
}
}現在,調用控制方法將返回 serve 方法的結果,如預期。
4. 結論
在本文中,我們觀察到一種非常常見的錯誤,即在無意中將 Spring 注入與我們通過調用其構造函數創建的對象混合時,會導致 NullPointerException 異常。我們通過避免這種責任混淆,並將我們之前自己管理的對象轉變為 Spring 管理的 Bean 來解決這個問題。