知識庫 / Spring RSS 訂閱

創建 Spring 運行時參數原型 Bean

Spring
HongKong
10
11:16 AM · Dec 06 ,2025

1. 概述

本文將介紹如何在 Spring 中創建具有運行時參數的原型作用域 Bean。

在 Spring 中,有多種 Bean 作用域可供選擇,默認作用域為 singleton,這意味着 singleton 作用域的 Bean 始終會產生相同對象。

或者,如果需要每次從容器中生成一個新的實例,我們可以使用 prototype 作用域的 Bean。然而,在大多數情況下,如果我們嘗試從 singleton Bean 中實例化 prototype Bean 或將動態參數傳遞給 prototype Bean 時,會遇到問題。

Spring 提供了多種方法來解決這些問題,我們將會在本教程中深入探討這些方法。

2. 創建具有動態參數的原型 Bean

我們有時需要使用動態參數作為輸入來初始化 Spring 中的 Bean。原型 Bean 可以通過多種方法,使用 Spring 賦予不同的動態參數。

我們將逐一探討它們各自的優缺點。

首先,讓我們創建一個原型 Bean Employee

public class Employee {
    private String name;

    public Employee(String name) {
        this.name = name;
    }

    public void printName() {
        System.out.println(name);
    }
}

讓我們為我們的 Employee 原型 Bean 創建一個配置:

@Configuration
public class EmployeeConfig {
    @Bean(name = "Employee")
    @Scope(BeanDefinition.SCOPE_PROTOTYPE)
    public Employee createPrototype(String name) {
        return new Employee(name);
    }
}

2.1. 使用應用上下文

通常,這是使用原型 Bean 的最基本且最簡單的方法,通過 ApplicationContext

讓我們將 ApplicationContext 注入到我們的組件中:

@Component
public class UseEmployeePrototype {
    private ApplicationContext applicationContext;

    @Autowired
    public UseEmployeePrototype(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

    public void usePrototype() {
        Employee employee = (Employee) applicationContext.getBean("Employee", "sachin");
        employee.printName();
    }
}

如我們所見,我們緊密地將 Bean 的創建與 ApplicationContext 耦合。因此,如果修改我們的 Bean 實現,這種方法可能會受到影響。

2.2. 使用工廠方法

Spring 提供了 `ObjectFactory 接口,用於按需生成指定類型的對象。

讓我們使用 <em>EmployeeFactory</em> 接口為我們的 <em>Employee</em> Bean 創建一個工廠:

public class EmployeeBeanUsingObjectFactory {
    @Autowired
    private ObjectFactory employeeObjectFactory;

    public Employee getEmployee() {
        return employeeObjectFactory.getObject();
    }
}

在這裏,每次調用 getEmployee() 方法,Spring 都會返回一個新的 Employee 對象。

2.3. 使用 @Lookup 標註

或者,使用依賴注入,通過使用帶有 @Lookup 標註的依賴注入方法來解決問題。任何帶有 @Lookup 標註的方法都將被 Spring 容器覆蓋,然後返回該方法的命名 Bean。

讓我們創建一個組件,並創建一個帶有 @Lookup 標註的方法,以獲取 Employee 對象:

@Component
public class EmployeeBeanUsingLookUp {
    @Lookup
    public Employee getEmployee(String arg) {
        return null;
    }
}

使用帶有 @Lookup 註解的方法,例如 getEmployee(),將被 Spring 覆蓋。 這樣,Bean 就被註冊到應用程序上下文中。 每次調用 getEmployee() 方法時,都會返回一個新的 Employee 實例。

Spring 將使用 CGLIB 生成字節碼,並且類和方法不能為 final。

現在,讓我們測試給定原型 Bean 中的 @Lookup 方法,並檢查它返回不同的實例:

@Test
public void givenPrototypeBean_WhenLookup_ThenNewInstanceReturn() {
    AbstractApplicationContext context = new AnnotationConfigApplicationContext(EmployeeConfig.class);
    EmployeeBeanUsingLookUp firstContext = context.getBean(EmployeeBeanUsingLookUp.class);
    EmployeeBeanUsingLookUp secondContext = context.getBean(EmployeeBeanUsingLookUp.class);
    Employee firstInstance = firstContext.getEmployee("sachin");
    Employee secondInstance = secondContext.getEmployee("kumar");
    Assert.assertTrue(firstInstance != secondInstance);
}

2.4. 使用 Function 功能

Spring 提供了另一種選項,Function,用於在運行時創建原型 Bean。 還可以將參數應用到新創建的原型 Bean 實例上。

首先,讓我們使用 Function 創建一個組件,其中將添加 name 字段到實例中:

@Component
public class EmployeeBeanUsingFunction {
    @Autowired
    private Function<String, Employee> beanFactory;

    public Employee getEmployee(String name) {
        Employee employee = beanFactory.apply(name);
        return employee;
    }
}

進一步,現在,讓我們在我們的 Bean 配置中添加一個新的 beanFactory()

@Configuration
public class EmployeeConfig {
    @Bean
    @Scope(value = "prototype")
    public Employee getEmployee(String name) {
        return new Employee(name);
    }

    @Bean
    public Function<String, Employee> beanFactory() {
        return name -> getEmployee(name);
    }
}

最後,我們將檢查實例是否不同:

@Test
public void givenPrototypeBean_WhenFunction_ThenNewInstanceReturn() {
    AbstractApplicationContext context = new AnnotationConfigApplicationContext(EmployeeConfig.class);
    EmployeeBeanUsingFunction firstContext = context.getBean(EmployeeBeanUsingFunction.class);
    EmployeeBeanUsingFunction secondContext = context.getBean(EmployeeBeanUsingFunction.class);
    Employee firstInstance = firstContext.getEmployee("sachin");
    Employee secondInstance = secondContext.getEmployee("kumar");
    Assert.assertTrue(firstInstance != secondInstance);
}

2.5. 使用 ObjectProvider

Spring 提供 ObjectProvider<T>,它是現有 ObjectFactory 接口的擴展。

下面演示如何注入 ObjectProvider 並使用它獲取 Employee 對象:

public class EmployeeBeanUsingObjectProvider {
    @Autowired
    private org.springframework.beans.factory.ObjectProvider objectProvider;

    public Employee getEmployee(String name) {
        Employee employee = objectProvider.getObject(name);
        return employee;
    }
}

現在,讓我們測試並檢查實例是否不同:

@Test
public void givenPrototypeBean_WhenObjectProvider_ThenNewInstanceReturn() {
    AbstractApplicationContext context = new AnnotationConfigApplicationContext(EmployeeConfig.class);
    EmployeeBeanUsingObjectProvider firstContext = context.getBean(EmployeeBeanUsingObjectProvider.class);
    EmployeeBeanUsingObjectProvider secondContext = context.getBean(EmployeeBeanUsingObjectProvider.class);
    Employee firstInstance = firstContext.getEmployee("sachin");
    Employee secondInstance = secondContext.getEmployee("kumar");
    Assert.assertTrue(firstInstance != secondInstance);
}

3. 結論

在本教程中,我們學習了多種動態創建原型作用域 Bean 的方法,這些方法適用於 Spring 框架。

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

發佈 評論

Some HTML is okay.