【Spring Boot 3】获取已注入的Bean
- 背景
- 介绍
- 开发环境
- 开发步骤及源码
- 工程目录结构
- 总结
背景
软件开发是一门实践性科学,对大多数人来说,学习一种新技术不是一开始就去深究其原理,而是先从做出一个可工作的DEMO入手。但在我个人学习和工作经历中,每次学习新技术总是要花费或多或少的时间、检索不止一篇资料才能得出一个可工作的DEMO,这占用了我大量的时间精力。因此本文旨在通过一篇文章即能还原出可工作的、甚至可用于生产的DEMO,期望初学者能尽快地迈过0到1的这一步骤,并在此基础上不断深化对相关知识的理解。
为达以上目的,本文会将开发环境、工程目录结构、开发步骤及源码尽量全面地展现出来,文字描述能简则简,能用代码注释的绝不在正文中再啰嗦一遍,正文仅对必要且关键的信息做重点描述。
介绍
本文介绍开发Spring Boot应用如何获取已注入的Bean实例。
开发环境
分类 | 名称 | 版本 |
---|---|---|
操作系统 | Windows | Windows 11 |
JDK | Oracle JDK | 21.0.1 |
IDE | IntelliJ IDEA | 2023.3.4 |
构建工具 | Apache Maven | 3.9.6 |
开发步骤及源码
1> 创建Maven工程,添加依赖。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.example</groupId>
<artifactId>springboot3-bean</artifactId>
<version>0.0.1</version>
</parent>
<artifactId>springboot3-bean-obtain</artifactId>
<properties>
<java.version>21</java.version>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring-boot.version>3.2.2</spring-boot.version>
<lombok.version>1.18.30</lombok.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2> 定义获取已注入Bean的核心类。
package org.example.springboot.manager;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
@Getter
@Slf4j
public class BeanManager implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
if (this.applicationContext == null) {
this.applicationContext = applicationContext;
}
}
/**
* 通过Bean名称获取
*/
public Object getBean(String name) {
try {
return this.applicationContext.getBean(name);
} catch (NoSuchBeanDefinitionException e) {
log.error(e.getMessage());
return null;
}
}
/**
* 通过Bean类型获取
* 如果存在同一类型的多个Bean实例则会抛出NoSuchBeanDefinitionException,异常信息:expected single matching bean but found 2
*/
public <T> T getBean(Class<T> clazz) {
try {
return this.applicationContext.getBean(clazz);
} catch (NoSuchBeanDefinitionException e) {
log.error(e.getMessage());
return null;
}
}
/**
* 通过Bean名称和类型获取
*/
public <T> T getBean(String name, Class<T> clazz) {
try {
return this.applicationContext.getBean(name, clazz);
} catch (NoSuchBeanDefinitionException e) {
log.error(e.getMessage());
return null;
}
}
}
3> 定义测试用的Bean。
package org.example.springboot.bean;
import lombok.AllArgsConstructor;
import lombok.Data;
@AllArgsConstructor
@Data
public class CustomBean {
private Integer id;
private String name;
}
4> 配置注入Bean。
package org.example.springboot.config;
import org.example.springboot.bean.CustomBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class CustomBeanConfig {
@Bean("beanX")
public CustomBean beanX() {
return new CustomBean(1, "Bean-X");
}
@Bean("beanY")
public CustomBean beanY() {
return new CustomBean(2, "Bean-X");
}
}
5> 创建单元测试。
package org.example.springboot.manager;
import jakarta.annotation.Resource;
import org.assertj.core.api.Assertions;
import org.example.springboot.bean.CustomBean;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class BeanManagerTests {
@Autowired
BeanManager beanManager;
@Resource(name = "beanX")
CustomBean beanX;
@Resource(name = "beanY")
CustomBean beanY;
@Test
void test() {
// Test get bean by name
Assertions.assertThat(beanManager.getBean("beanX")).isSameAs(beanX);
Assertions.assertThat(beanManager.getBean("beanY")).isSameAs(beanY);
// Test get bean by type
Assertions.assertThat(beanManager.getBean(CustomBean.class)).isNull();
// Test get bean by name and type
Assertions.assertThat(beanManager.getBean("beanX", CustomBean.class)).isSameAs(beanX);
Assertions.assertThat(beanManager.getBean("beanY", CustomBean.class)).isSameAs(beanY);
}
}
6> 单元测试结果。
工程目录结构
总结
测试用的Bean和配置注入放在 src/test
目录下是为了辅助测试。