SpringBoot這些異常你知道原因嗎?你遇過到幾個?
環(huán)境:SpringBoot3.2.5
1. 簡介
在篇文章,我們將詳細討論 BeanCreationException 異常。這是 BeanFactory 在創(chuàng)建定義的 Bean 時遇到問題時拋出的一種非常常見的異常。本文將探討導致這種異常的最常見原因以及解決方案。
2. 異常分類
2.1 NoSuchBeanDefinitionException
該異常的原因是 Spring 嘗試注入一個容器中不存在的 Bean,如下示例:
public class UserDAO {}
@Service
public class UserService {
@Resource
private UserDAO dao ;
}
這里UserDAO類上并沒有添加任何注解,當啟動容器時,拋出如下錯誤
圖片
遇到該異常,那你就要檢查UserDAO類上是否添加了@Component, @Repository, @Service, @Controller, 這些注解(或者配置類中使用@Bean)。還有一點是,當前這個類所在的包在當前掃描的范圍內。
2.2 NoUniqueBeanDefinitionException
該異常的原因是 Spring 在注入某個抽象類(接口)時,發(fā)現容器中存在多個,如下示例:
public interface DAO {}
@Component
public class CommonDAO implements DAO {}
@Component
public class PersonDAO implements DAO {}
@Service
public class UserService {
@Resource
private DAO dao ;
}
啟動容器后,拋出如下錯誤
圖片
解決辦法就是指定名稱,上面使用的@Resource可以指定name屬性
@Service
public class UserService {
@Resource(name = "personDAO")
private DAO dao ;
}
如果你使用的@Autowired,那么你可以使用@Qualifier
2.3 BeanInstantiationException
出現該異常的原因是在創(chuàng)建實例對象時,如下示例:
創(chuàng)建對象拋出了異常
@Controller
public class UserController {
public UserController() {
// TODO
throw new RuntimeException("異常了") ;
}
}
在構造函數中,執(zhí)行相關的操作時,拋出了異常,錯誤信息如下:
圖片
抽象類定義為Bean
@Controller
public abstract class UserController {
public UserController() {
}
}
拋出錯誤如下:
圖片
根據異常信息提示,已經告訴你是否是抽象類。
2.4 NoSuchBeanDefinitionException
如果一個 Bean 沒有默認構造函數(無參的),而是定義了有參的構造函數,那么如果容器中不存在參數類型的bean,那么會拋出該異常,如下示例:
@Component
public class User {
public User(String name) {
System.out.println(name) ;
}
}
拋出異常
圖片
檢查容器中是否有一個String類型的Bean對象。
2.5 NotWritablePropertyException
該異常出現的概率非常小,因為我們現在都是基于注解的方式去配置bean,很少使用xml方式,除了xml方式為,我們還可以通過注冊BeanDefinition方式來來注冊Bean,接下來我們通過注冊BeanDefinition方式來設置bean的相關屬性,如下示例:
public class UserService {
private DAO dao ;
}
該類并沒有對dao屬性定義setter方法。接下來,通過如下方式注冊上面的Bean對象:
ConfigurableApplicationContext context = ...
context.registerBean("userService", UserService.class, bd -> {
bd.getPropertyValues().add("dao", xxx) ;
}) ;
通過BeanDefinition方式注冊bean,并添加屬性,運行程序后拋出如下錯誤:
圖片
2.6 BeanCurrentlyInCreationException
該異常通常發(fā)生在使用構造器注入時,例如循環(huán)依賴的情況下,如下示例:
@Component
public class A {
public A(B b) {}
}
@Component
public class B {
public B(A a) {
}
}
拋出如下錯誤
異常信息中已經描述了,是否是循環(huán)依賴,解決改異常,可以在任意一方使用@Lazy注解即可,如下示例:
public class A {
public A(@Lazy B b) {}
}
這里只需要在任何一方的參數上添加@Lazy注解即可解決該循環(huán)依賴問題。
2.7 BeanDefinitionOverrideException
當容器中出現beanName相同的情況(不允許覆蓋),則拋出該異常,如下示例:
@Component("xxxooo")
public class A {
}
@Component("xxxooo")
public class B {
}
這里定義了2個beanName都為xxxooo的對象,默認情況下,springboot是不允許覆蓋的,如下屬性配置:
spring:
main:
allow-bean-definition-overriding: false
在這種情況下,啟動時將拋出如下錯誤:
圖片
當設置為true,以后,容器中將存在的將是xxxooo=com.pack.B。后面的會覆蓋前面定義的bean。