知識庫 / Spring RSS 訂閱

lombok 使用 Spring 中的構造器注入

Spring
HongKong
9
02:41 PM · Dec 06 ,2025

1. 簡介

Lombok 是一個極有用的庫,它能夠消除冗餘代碼。如果您尚未熟悉它,我強烈建議您查看之前的教程——《項目 Lombok 簡介》。

在本文中,我們將演示它與 Spring 的 基於構造函數的依賴注入 結合使用的實用性。

2. 基於構造函數的依賴注入

使用 constructor-based Dependency Injection,在 Spring 中實現依賴注入的一種有效方法。這種方法強制我們明確地通過構造函數傳遞組件的依賴項。

Field-Based Dependency Injection 相比,它還提供了許多優勢:

  • 無需創建測試特定的配置組件——依賴項在構造函數中明確注入
  • 一致的設計——所有必需的依賴項由構造函數定義強調並管理
  • 簡單的單元測試——減少了 Spring Framework 的開銷
  • 可以自由使用 final 關鍵字

然而,由於需要編寫構造函數,因此它通常會導致代碼庫顯著增大。 考慮 GreetingServiceFarewellService 的兩個示例:

@Component
public class GreetingService {

    @Autowired
    private Translator translator;

    public String produce() {
        return translator.translate("hello");
    }
}
@Component
public class FarewellService {

    private final Translator translator;

    public FarewellService(Translator translator) {
        this.translator = translator;
    }

    public String produce() {
        return translator.translate("bye");
    }
}

基本上,這兩個組件的作用相同——它們都調用一個可配置的 翻譯器,傳遞一個特定任務的詞語。

然而,第二種變體則更加晦澀,這是由於構造函數的樣板代碼造成的,這些代碼並沒有為代碼帶來任何實際價值。

翻譯器 annotation.

3. 使用 Lombok 進行構造器注入

藉助 Lombok,您可以為任何類的所有字段生成構造器(使用 @AllArgsConstructor)或所有 final 類字段的構造器(使用 @RequiredArgsConstructor)。 此外,如果您仍然需要一個空構造器,則可以附加一個額外的 @NoArgsConstructor 註解。

讓我們創建一個第三個組件,類似於前兩個組件:

@Component
@RequiredArgsConstructor
public class ThankingService {

    private final Translator translator;

    public String produce() {
        return translator.translate("thank you");
    }
}

上面的註解會導致 Lombok 生成一個構造函數:

@Component
public class ThankingService {

    private final Translator translator;

    public String thank() {
        return translator.translate("thank you");
    }

    /* Generated by Lombok */
    public ThankingService(Translator translator) {
        this.translator = translator;
    }
}

4. 多個構造函數

構造函數不必進行標註,只要在一個組件中只有一個,Spring 就能明確地選擇它來實例化一個新的對象。一旦出現多個構造函數,您還需要標註用於由 IoC 容器使用的那個。

請考慮 ApologizeService 示例:

@Component
@RequiredArgsConstructor
public class ApologizeService {

    private final Translator translator;
    private final String message;

    @Autowired
    public ApologizeService(Translator translator) {
        this(translator, "sorry");
    }

    public String produce() {
        return translator.translate(message);
    }
}

上述組件可選擇性地配置 message 字段,該字段在組件創建後無法更改(因此沒有 setter 方法)。因此,我們需要提供兩個構造函數——一個具有完整配置,另一個具有隱式的默認 message 值。

除非一個構造函數被標記為使用 @Autowired@Inject@Resource,否則 Spring 將拋出錯誤。

Failed to instantiate [...]: No default constructor found;

如果我們要對 Lombok 生成的構造函數進行註解,則需要通過將註解傳遞給 @AllArgsConstructoronConstructor 參數來實現:

@Component
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class ApologizeService {
    // ...
}

onConstructor 參數接受一個註解數組(或在特定示例中,單個註解),用於在生成的構造函數上添加。雙下劃線命名法是為了兼容性問題而引入的。根據文檔:

這種怪異的語法是為了使該功能在 javac 7 編譯器中工作,@__ 類型是對註解類型 __ (雙下劃線) 的引用,實際上 __ 類型並不存在;這使得 javac 7 延遲終止編譯過程,因為一個註解處理器可能會稍後創建 __ 類型。

5. 總結

在本教程中,我們展示了在構造方法注入和基於字段的注入之間,無需偏愛基於字段的注入以減少樣板代碼的問題。

藉助Lombok,可以在不影響運行時性能的情況下自動化常見的代碼生成,將冗長、晦澀的代碼縮短為單行註解。

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

發佈 評論

Some HTML is okay.