知識庫 / Spring RSS 訂閱

將 Spring Bean 設置為 Null

Spring
HongKong
2
11:22 AM · Dec 06 ,2025

1. 概述

本教程將教你如何在 Spring 上下文中將 Bean 設置為 null。 這在某些情況下可能很有用,例如在測試中,我們不想提供 Mock 對象。 此外,在使用一些可選功能時,我們可能希望避免創建實現並傳遞 null

此外,通過這種方式,我們可以創建佔位符,以便在 Bean 生命週期之外決定選擇所需的實現。 最後,這種技術可能是廢棄過程的第一步,該過程涉及從上下文中刪除特定的 Bean。

2. 組件設置

有幾種方法可以設置一個 Bean 為 null,具體取決於上下文的配置方式。 我們將考慮 XML、註解和 Java 配置。 我們將使用一個簡單的設置,包含兩個類:

@Component
public class MainComponent {
    private SubComponent subComponent;
    public MainComponent(final SubComponent subComponent) {
        this.subComponent = subComponent;
    }
    public SubComponent getSubComponent() {
        return subComponent;
    }
    public void setSubComponent(final SubComponent subComponent) {
        this.subComponent = subComponent;
    }
}

我們演示如何將 SubComponent 設置為 null 在 Spring 上下文中:

@Component
public class SubComponent {}

3. 使用佔位符進行XML配置

在XML配置中,我們可以使用一個特殊佔位符來標識null 值:

<beans>
    <bean class="com.baeldung.nullablebean.MainComponent" name="mainComponent">
        <constructor-arg>
            <null/>
        </constructor-arg>
    </bean>
</beans>

以下配置將產生以下結果:

@Test
void givenNullableXMLContextWhenCreatingMainComponentThenSubComponentIsNull() {
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
      "nullable-application-context.xml");
    MainComponent bean = context.getBean(MainComponent.class);
    assertNull(bean.getSubComponent());
}

4. 使用 SpEL 進行 XML 配置

我們可以使用 SpEL 達到類似的結果,在 XML 中實現。與之前的配置相比,會有一些差異:

<beans>
    <bean class="com.baeldung.nullablebean.MainComponent" name="mainComponent">
        <constructor-arg value="#{null}"/>
    </bean>
</beans>

同樣地,與上次測試類似,我們可以發現 SubComponentnull

@Test
void givenNullableSpELXMLContextWhenCreatingMainComponentThenSubComponentIsNull() {
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
      "nullable-spel-application-context.xml");
    MainComponent bean = context.getBean(MainComponent.class);
    assertNull(bean.getSubComponent());
}

5. 使用 SpEL 和屬性進行 XML 配置

一種改進先前解決方案的方法是,將 bean 名稱存儲在屬性文件中。 這樣,我們可以在需要時傳遞 null 值,而無需更改配置:

nullableBean = null

XML 配置將使用 > 來讀取屬性:

<beans>
    <bean id="propertyConfigurer"
      class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="location" value="classpath:nullable.properties"/>
    </bean>
    <bean class="com.baeldung.nullablebean.MainComponent" name="mainComponent">
        <constructor-arg value="#{ ${nullableBean} }"/>
    </bean>
    <bean class="com.baeldung.nullablebean.SubComponent" name="subComponent"/>
</beans>

然而,我們應該在 SpEL 表達式中使用屬性佔位符,以確保值能夠正確讀取。 結果,我們將初始化 SubComponentnull

@Test
void givenNullableSpELXMLContextWithNullablePropertiesWhenCreatingMainComponentThenSubComponentIsNull() {
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
      "nullable-configurable-spel-application-context.xml");
    MainComponent bean = context.getBean(MainComponent.class);
    assertNull(bean.getSubComponent());
}

為了提供實現,我們需要僅修改以下屬性:

nullableBean = subComponent

6. Java 配置中的空供應商 (Null Supplier)

無法直接從帶有 @Bean</em/> 註解的類的方法中返回 null</em/>。因此,我們需要以某種方式將其包裝起來。我們可以使用 Supplier</em/> 來實現:

@Bean
public Supplier<SubComponent> subComponentSupplier() {
    return () -> null;
}

從技術角度來看,我們可以使用任何類來包裝一個 null 值,但使用 Supplier 更具表達力。 在處理 null 值時,我們並不關心 Supplier 是否會被多次調用。 但是,如果我們想為常規 Bean 實現類似解決方案,則必須確保 Supplier 在需要單例的情況下提供相同實例。

這個解決方案也將提供正確的行為:

@Test
void givenNullableSupplierContextWhenCreatingMainComponentThenSubComponentIsNull() {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
      NullableSupplierConfiguration.class);
    MainComponent bean = context.getBean(MainComponent.class);
    assertNull(bean.getSubComponent());
}

請注意,僅僅從 @Bean 返回 null 可能會導致問題:

@Bean
public SubComponent subComponent() {
    return null;
}

在這種情況下,上下文會因為 UnsatisfiedDependencyException 失敗:

@Test
void givenNullableContextWhenCreatingMainComponentThenSubComponentIsNull() {
    assertThrows(UnsatisfiedDependencyException.class, () ->  new AnnotationConfigApplicationContext(
      NullableConfiguration.class));
}

7. 使用 可選

當使用 可選 時,Spring 會自動識別該 Bean 可能不在上下文中存在,並且無需任何額外的配置,便會傳遞 null

@Bean
public MainComponent mainComponent(Optional<SubComponent> optionalSubComponent) {
    return new MainComponent(optionalSubComponent.orElse(null));
}

如果 Spring 無法在上下文中找到 SubComponent,它將傳遞一個空 Optional

@Test
void givenOptionableContextWhenCreatingMainComponentThenSubComponentIsNull() {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
      OptionableConfiguration.class);
    MainComponent bean = context.getBean(MainComponent.class);
    assertNull(bean.getSubComponent());
}

8. 非必需的自動注入

另一種使用 null 作為 Bean 值的做法是聲明它為非必需的。但是,這種方法僅適用於非構造注入。

@Component
public class NonRequiredMainComponent {
    @Autowired(required = false)
    private NonRequiredSubComponent subComponent;
    public NonRequiredSubComponent getSubComponent() {
        return subComponent;
    }
    public void setSubComponent(final NonRequiredSubComponent subComponent) {
        this.subComponent = subComponent;
    }
}

該依賴項對於組件的正常運行並不必要:

@Test
void givenNonRequiredContextWhenCreatingMainComponentThenSubComponentIsNull() {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
      NonRequiredConfiguration.class);
    NonRequiredMainComponent bean = context.getBean(NonRequiredMainComponent.class);
    assertNull(bean.getSubComponent());
}

9. 使用 @Nullable 註解

此外,我們可以使用 @Nullable 註解來標識我們期望該 Bean 可能為 null. Spring 和 Jakarta 標註都會對該功能支持。

@Component
public class NullableMainComponent {
    private NullableSubComponent subComponent;
    public NullableMainComponent(final @Nullable NullableSubComponent subComponent) {
        this.subComponent = subComponent;
    }
    public NullableSubComponent getSubComponent() {
        return subComponent;
    }
    public void setSubComponent(final NullableSubComponent subComponent) {
        this.subComponent = subComponent;
    }
}

我們不需要將 NullableSubComponent 識別為 Spring 組件:

public class NullableSubComponent {}

Spring 上下文會將其設置為 null,基於@Nullable註解:

@Test
void givenContextWhenCreatingNullableMainComponentThenSubComponentIsNull() {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
      NullableJavaConfiguration.class);
    NullableMainComponent bean = context.getBean(NullableMainComponent.class);
    assertNull(bean.getSubComponent());
}

10. 結論

在 Spring 上下文中,使用 nulls 並非最常見的做法,但在某些情況下,這可能是合理的。然而,將 Bean 設置為 null 的過程可能並不直觀。

在本文中,我們學習了通過多種方式解決此問題。

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.