1

Spring中创建带原型作用域bean5种方法

 5 months ago
source link: https://www.jdon.com/73112.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Spring中创建带原型作用域bean5种方法

在这篇简短的文章中,我们将学习如何在 Spring 中创建带有运行时参数的原型作用域(prototype-scoped) bean。

在Spring中,有许多不同的bean作用域,但默认作用域是单例,这意味着单例作用域的bean将始终生成相同的对象。

或者,如果每次都需要来自容器的新实例,我们可以使用原型范围的 bean。然而,在大多数情况下,如果我们想要从单例 bean 实例化原型或将动态参数传输到原型 bean,我们会遇到问题。

Spring 提供了许多方法来实现这些目标,我们将在本教程中深入讨论。

使用动态参数创建原型 Bean
有时我们需要在每次初始化时使用动态参数作为输入来初始化 Spring bean。可以使用多种方法通过 Spring 为原型 bean 分配不同的动态参数。

我们将一一分析它们,看看它们的优点和缺点。

首先,我们先创建一个原型 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);
    }
}

1.使用应用程序上下文
一般来说,这是使用ApplicationContext获取原型 bean 的最基本、最简单的方法。

让我们将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.使用工厂方法
Spring 提供了 ObjectFactory<T> 接口来按需生成给定类型的对象。

让我们使用ObjectFactory为Employee bean 创建一个EmployeeFactory:

public class EmployeeBeanUsingObjectFactory {
    @Autowired
    private ObjectFactory employeeObjectFactory;
    public Employee getEmployee() {
        return employeeObjectFactory.getObject();
    }
}

在这里,每次调用getEmployee()时,Spring 都会返回一个新的Employee对象。

3.使用@Lookup
或者,使用@Lookup 注释的方法注入可以解决该问题。我们使用@Lookup注释注入的任何方法都将被Spring容器覆盖,然后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);
}

4.使用Function
Spring 提供了另一个选项Function,用于在运行时创建原型 bean。我们还可以将参数应用于新创建的原型 bean 实例。

首先,让我们使用Function创建一个组件,其中名称字段将添加到实例中:

@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);
}

5.使用ObjectProvider
Spring 提供了ObjectProvider<T> ,它是现有ObjectFactory接口的扩展。

让我们注入 ObjectProvider并使用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);
}

 


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK