環(huán)境:Spring5.3.23
1. 簡介
在Spring框架中,依賴注入是實現(xiàn)組件間解耦的重要手段。然而,當(dāng)嘗試注入一個不存在的Bean時,程序通常會報錯,這可能導(dǎo)致應(yīng)用程序無法正常啟動。
為了解決這個問題,我們將介紹一些最佳實踐和技巧,幫助開發(fā)者在編寫代碼時避免此類錯誤。例如,通過@Autowired(required = false)將required設(shè)置為false或者通過Optional來避免此類異常情況。但是本文將要介紹另外一種解決辦法。
2. 重現(xiàn)錯誤
static class PersonDAO {
}
@Component
static class PersonService {
@Autowired
private PersonDAO dao ;
public void find(Integer id) {
System.out.println("id = " + id.toString()) ;
}
}
上面的PersonDAO類并沒有被注冊為Bean,但在PersonService類中使用了@Autowired進(jìn)行注入,在這種情況下程序啟動就會報錯。
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.pack.mAIn.autowired_resource.ResourceInjectAndNullableMain2$PersonDAO' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.JAVA:1801)
錯誤意思就是期望一個PersonDAO,但是容器中并沒有這個類。
如果真有這種情況,要解決這個問題我們可以通過設(shè)置@Autowired屬性required為false。這樣啟動就不會報錯了。當(dāng)然這是其中一種方法,其實還有其它的方式解決。
- 【Spring揭秘】ObjectProvider:讓依賴注入更加靈活和安全這篇文章詳細(xì)的介紹了如何使用ObjectProvider
- Optional
- ObjectFactory這種方式會在調(diào)用getObject方法的時候報錯(如果不存在時)。
通過上面3中方式都可以解決當(dāng)不存在的時候,容器啟動不至于報錯。但是今天我們可不是講這些。今天我們要將的是@Nullable注解
3. @Nullable注解
直接上代碼,示例1:
@Nullable
@Autowired
private PersonDAO dao ;
通過該注解程序啟動將不會報錯了,我這里使用的是spring包下的。org.springframework.lang.Nullable。
示例2:
@javax.annotation.Nullable
@Autowired
private PersonDAO dao ;
程序同樣正常啟動
是不是說只要加了Spring的或者是java自己的@Nullable就可以了呢?接著往下看
示例3:
自定義Nullable注解
@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
static @interface Nullable {
}
接著使用上面自定義的注解,發(fā)現(xiàn)程序啟動也不會報錯。是不是很神奇?Spring又是如何處理的呢?
4. 原理
Spring在注入一個對象時都,在這個過程中它會將你要注入的對象包裝成DependencyDescriptor,在該類中有個isRequire方法
public class DependencyDescriptor extends InjectionPoint {
// 判斷注入對象是不是必須的
public boolean isRequired() {
// 是否對@Autuwored配置了required屬性,設(shè)置為false。
if (!this.required) {
return false;
}
if (this.field != null) {
// hasNullableAnnotation判斷是否有@Nullable注解
return !(this.field.getType() == Optional.class || hasNullableAnnotation() ||
(KotlinDetector.isKotlinReflectPresent() &&
KotlinDetector.isKotlinType(this.field.getDeclaringClass()) &&
KotlinDelegate.isNullable(this.field)));
} else {
return !obtainMethodParameter().isOptional();
}
}
private boolean hasNullableAnnotation() {
// 遍歷字段上的所有注解
for (Annotation ann : getAnnotations()) {
// 這里的判斷,僅僅是判斷你的類名是否為Nullable,并不關(guān)心具體是哪個包下的注解
if ("Nullable".equals(ann.annotationType().getSimpleName())) {
return true;
}
}
return false;
}
}
我們還可以將注解加到方法參數(shù)上,一樣是生效的
@Autowired
public void setDao(@Nullable PersonDAO dao) {
this.dao = dao ;
}
總結(jié):在Spring框架中,@Nullable注解為我們提供了一種機(jī)制來處理可能為null的字段或參數(shù)。通過使用@Nullable,我們可以明確告知Spring容器某字段或參數(shù)可能是null,從而避免因未注入而導(dǎo)致的運行時錯誤。
@Nullable注解的使用非常簡單,只需在字段,方法參數(shù)上添加該注解即可。Spring會在依賴注入時檢查是否存在相應(yīng)的字段,如果不存在,則不會拋出異常,而是將該類或字段的值設(shè)置為null。
完畢!!!