Spring 5:以函数式方式注册 Bean

http://www.baeldung.com/spring-5-functional-beans
作者:Loredana Crusoveanu
译者:http://oopsguy.com

1、概述

Spring 5 支持在应用程序上下文中以函数式方式注册 bean。

简单地说,您可以通过在 GenericApplicationContext 类中定义的一个新 registerBean() 方法重载来完成。

让我们来为此功能列举一些例子。

2、Maven 依赖

建立 Spring 5 项目的最快方式是将 spring-boot-start-parent 依赖添加到 pom.xml 中来使用 Spring Boot:

1
2
3
4
5
6
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.0.M1</version>
<relativePath />
</parent>

我们的示例需要到 spring-boot-starter-webspring-boot-starter-test,且在 JUnit 测试中需要使用到 WebApplicationContext:

1
2
3
4
5
6
7
8
9
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>

当然,使用函数式的方式来注册一个 bean,Spring Boot 并不是必需的。 我们也可以直接添加 spring-core 依赖 [1]:

1
2
3
4
5
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.0.0.RC2</version>
</dependency>

由于 Maven Central 仓库中尚未存在这些版本 [1],我们需要将 Spring Snapshot Repository 添加到 pom.xml 文件中:

1
2
3
4
5
6
7
8
9
10
<repositories>
<repository>
<id>spring-snapshot</id>
<name>Spring Snapshot Repository</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>

3、以函数式形式注册 Bean

registerBean() API 可以接收两种类型的函数式接口作为参数:

  • 用于创建对象的 Supplier 参数
  • 一个 BeanDefinitionCustomizer vararg(可变参数),可用于提供一个或多个 lambda 表达式来自定义 BeanDefinition;此接口有一个 custom() 方法

首先,我们创建一个非常简单的类,使用它来创建 bean:

1
2
3
4
5
public class MyService {
public int getRandomNumber() {
return new Random().nextInt(10);
}
}

我们再添加一个 @SpringBootApplication 类,可以使用它来运行 JUnit 测试:

1
2
3
4
5
6
@SpringBootApplication
public class Spring5Application {
public static void main(String[] args) {
SpringApplication.run(Spring5Application.class, args);
}
}

接下来,我们可以使用 @SpringBootTest 注解设置我们的测试类来创建一个 GenericWebApplicationContext 实例:

1
2
3
4
5
6
7
8
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Spring5Application.class)
public class BeanRegistrationTest {
@Autowired
private GenericWebApplicationContext context;

//...
}

我们在示例中使用了 GenericWebApplicationContext 类型,但任何类型的 ApplicationContext 都可以以相同的方式来注册一个 bean。

让我们看看如何使用 lambda 表达式注册一个 bean 以创建实例

1
context.registerBean(MyService.class, () -> new MyService());

我们来验证一下可不可以检索到该 bean 并使用它:

1
2
3
MyService myService = (MyService) context.getBean("com.baeldung.functional.MyService"); 

assertTrue(myService.getRandomNumber() < 10);

在该例子中我们可以看到,如果没有明确定义 bean 的名称,那么它将根据小写的类名来确定。上述方法也可以与一个显式的 bean 名称一起使用:

1
context.registerBean("mySecondService", MyService.class, () -> new MyService());

接下来,让我们来看看如何通过添加一个 lambda 表达式来自定义注册一个 bean

1
2
context.registerBean("myCallbackService", MyService.class, 
() -> new MyService(), bd -> bd.setAutowireCandidate(false));

这个参数是一个函数式回调,我们可以使用它来设置 bean 属性,如 autowire-candidate 标志或 primary 标志。

4、结论

在本教程中,我们了解了如何以函数式方式来注册一个 bean。

该示例的源代码可以在 GitHub 上找到。

原文示例代码

https://github.com/eugenp/tutorials/tree/master/spring-5

译者注

  • [1] 原作者在编写该文时 Spring 5 还没有正式版本。就在不久前,Spring 5 已经发布了,您现在可以直接使用最新的 Spring 5 发行版本。