知識庫 / Spring RSS 訂閱

Spring @Lookup 註解

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

1. 引言

在本快速教程中,我們將探討 Spring 框架中通過 @Lookup 註解提供的基於方法的依賴注入支持。

2. 為什麼使用 >?

標註了 的方法告訴 Spring 在調用該方法時,返回其返回類型的實例。

本質上,Spring 會覆蓋我們標註的方法,並使用其返回類型和參數作為 BeanFactory#getBean 的參數。

@Lookup 有以下用途:

  • 將原型作用域的 Bean 注入到單例 Bean 中(類似於
  • 程序化注入依賴

此外,@Lookup 是 Java 中 XML 元素的對應項。

3. 使用 @Lookup 標籤

3.1. 將原型作用域的 Bean 注入到單例 Bean 中

如果我們決定擁有一個原型作用域的 Spring Bean,那麼我們幾乎立刻就會面臨一個問題:我們的單例 Spring Bean 將如何訪問這些原型作用域的 Spring Bean?

現在,Provider 確實是一種方法,但 @Lookup 在某些方面更具靈活性。

首先,讓我們創建一個原型 Bean,稍後將其注入到單例 Bean 中:

@Component
@Scope("prototype")
public class SchoolNotification {
    // ... prototype-scoped state
}

如果創建一個使用 @Lookup</em/> 的單例 Bean,則:

@Component
public class StudentServices {

    // ... member variables, etc.

    @Lookup
    public SchoolNotification getNotification() {
        return null;
    }

    // ... getters and setters
}

使用 @Lookup,我們可以通過我們的單例 Bean 獲取 SchoolNotification 實例:

@Test
public void whenLookupMethodCalled_thenNewInstanceReturned() {
    // ... initialize context
    StudentServices first = this.context.getBean(StudentServices.class);
    StudentServices second = this.context.getBean(StudentServices.class);
       
    assertEquals(first, second); 
    assertNotEquals(first.getNotification(), second.getNotification()); 
}

請注意,在 StudentServices 中,我們保留了 getNotification 方法為佔位符。

這是因為 Spring 通過調用 beanFactory.getBean(StudentNotification.class) 覆蓋了該方法,因此我們可以將其留空。

3.2. 流程注入依賴

更強大的是,@Lookup 允許我們流程注入依賴,這與 Provider 無法實現的功能不同。

讓我們為 StudentNotification 添加一些狀態:

@Component
@Scope("prototype")
public class SchoolNotification {
    @Autowired Grader grader;

    private String name;
    private Collection<Integer> marks;

    public SchoolNotification(String name) {
        // ... set fields
    }

    // ... getters and setters

    public String addMark(Integer mark) {
        this.marks.add(mark);
        return this.grader.grade(this.marks);
    }
}

現在,這取決於一些 Spring 上下文以及我們程序化提供的額外上下文。

我們可以向 StudentServices 添加一個方法,該方法接受學生數據並將其持久化:

public abstract class StudentServices {
 
    private Map<String, SchoolNotification> notes = new HashMap<>();
 
    @Lookup
    protected abstract SchoolNotification getNotification(String name);

    public String appendMark(String name, Integer mark) {
        SchoolNotification notification
          = notes.computeIfAbsent(name, exists -> getNotification(name)));
        return notification.addMark(mark);
    }
}

在運行時,Spring 將以相同的方式執行該方法,並使用一些額外的技巧。

首先,請注意,它還可以調用複雜的構造函數,並注入其他 Spring Bean,從而使 SchoolNotification 更加像一個具有 Spring 意識的方法。

它通過實現 getSchoolNotification 方法,並通過調用 beanFactory.getBean(SchoolNotification.class, name) 來完成。

其次,我們有時可以將帶有 @Lookup- 註解的方法聲明為抽象方法,如上面的示例所示。

使用 abstract 比使用 stub 更美觀,但我們只能在不進行 component-scan 或使用 @Bean 管理周圍 Bean 的情況下使用它。

@Test
public void whenAbstractGetterMethodInjects_thenNewInstanceReturned() {
    // ... initialize context

    StudentServices services = context.getBean(StudentServices.class);    
    assertEquals("PASS", services.appendMark("Alex", 89));
    assertEquals("FAIL", services.appendMark("Bethany", 78));
    assertEquals("PASS", services.appendMark("Claire", 96));
}

通過這種配置,我們可以將 Spring 依賴項以及方法依賴項添加到 SchoolNotification 中。

4. 侷限性

儘管 @Lookup 具有很高的靈活性,但仍有一些值得注意的侷限性:

  • @Lookup 註解的方法,例如 getNotification,當週圍的類(例如 Student)進行組件掃描時,必須是具體的。這是因為組件掃描會跳過抽象的 Bean。
  • 使用 @Lookup 註解的方法在周圍的類是 @Bean 管理的類中將無法正常工作。

在這些情況下,如果我們需要將原型 Bean 注入到單例中,我們可以考慮使用 Provider 作為替代方案。

5. 結論

在本文中,我們學習了何時以及如何使用 Spring 框架中的 <em @Lookup</em> 註解,包括如何使用它將原型作用域的 Bean 注入到單例 Bean 中,以及如何使用它通過程序注入依賴。

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

發佈 評論

Some HTML is okay.