Java 实现SpringContextUtils工具类,手动获取Bean
SpringContextUtils 工具类实现
下面是一个完整的 Spring 上下文工具类实现,用于从 Spring 容器中获取 Bean。这个工具类考虑了线程安全、性能优化和易用性,并提供了多种获取 Bean 的方式。
完整实现代码
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;import java.util.Map;/*** Spring 上下文工具类,用于获取容器中的Bean* * 功能包括:* 1. 获取ApplicationContext* 2. 通过名称获取Bean* 3. 通过类型获取Bean* 4. 通过名称和类型获取Bean* 5. 获取指定类型的所有Bean* 6. 获取当前环境配置*/
@Component
public class SpringContextUtils implements ApplicationContextAware {/*** 静态ApplicationContext*/private static ApplicationContext applicationContext;/*** 设置ApplicationContext*/@Overridepublic void setApplicationContext(@Nullable ApplicationContext applicationContext) throws BeansException {if (SpringContextUtils.applicationContext == null) {SpringContextUtils.applicationContext = applicationContext;}}/*** 获取ApplicationContext*/public static ApplicationContext getApplicationContext() {checkApplicationContext();return applicationContext;}/*** 通过名称获取Bean* @param name Bean名称* @return Bean实例*/@SuppressWarnings("unchecked")public static <T> T getBean(String name) {checkApplicationContext();return (T) applicationContext.getBean(name);}/*** 通过类型获取Bean* @param clazz Bean类型* @return Bean实例*/public static <T> T getBean(Class<T> clazz) {checkApplicationContext();return applicationContext.getBean(clazz);}/*** 通过名称和类型获取Bean* @param name Bean名称* @param clazz Bean类型* @return Bean实例*/public static <T> T getBean(String name, Class<T> clazz) {checkApplicationContext();return applicationContext.getBean(name, clazz);}/*** 获取指定类型的所有Bean* @param clazz Bean类型* @return Bean名称与实例的映射*/public static <T> Map<String, T> getBeansOfType(Class<T> clazz) {checkApplicationContext();return applicationContext.getBeansOfType(clazz);}/*** 获取当前环境配置* @param key 配置键* @return 配置值*/public static String getProperty(String key) {checkApplicationContext();return applicationContext.getEnvironment().getProperty(key);}/*** 检查ApplicationContext是否已注入*/private static void checkApplicationContext() {if (applicationContext == null) {throw new IllegalStateException("ApplicationContext未注入,请在Spring配置中定义SpringContextUtils");}}
}
功能说明
1. 核心功能
- 获取 ApplicationContext:
getApplicationContext()
- 通过名称获取 Bean:
getBean(String name)
- 通过类型获取 Bean:
getBean(Class<T> clazz)
- 通过名称和类型获取 Bean:
getBean(String name, Class<T> clazz)
- 获取指定类型的所有 Bean:
getBeansOfType(Class<T> clazz)
- 获取环境配置:
getProperty(String key)
2. 线程安全性
- 使用静态变量存储 ApplicationContext,保证全局唯一
- 通过
@Component
注解让 Spring 管理工具类实例 - 实现
ApplicationContextAware
接口自动注入上下文
3. 异常处理
- 检查 ApplicationContext 是否已注入,未注入时抛出明确异常
- 使用
@Nullable
注解标记可为空的参数 - 添加泛型支持,减少类型转换
使用示例
1. 基本使用
// 获取ApplicationContext
ApplicationContext context = SpringContextUtils.getApplicationContext();// 通过名称获取Bean
UserService userService = SpringContextUtils.getBean("userService");// 通过类型获取Bean
UserService userService = SpringContextUtils.getBean(UserService.class);// 通过名称和类型获取Bean
UserService userService = SpringContextUtils.getBean("userService", UserService.class);
2. 获取所有同类型Bean
// 获取所有实现UserService接口的Bean
Map<String, UserService> userServices = SpringContextUtils.getBeansOfType(UserService.class);userServices.forEach((name, service) -> {System.out.println("Bean名称: " + name + ", 实例: " + service);
});
3. 获取环境配置
// 获取application.properties/yml中的配置
String appName = SpringContextUtils.getProperty("spring.application.name");
String serverPort = SpringContextUtils.getProperty("server.port");
高级用法
1. 在非Spring管理的类中使用
public class NonSpringClass {public void someMethod() {// 获取Spring容器中的BeanUserRepository repository = SpringContextUtils.getBean(UserRepository.class);repository.save(new User());}
}
2. 在静态方法中使用
public class UtilityClass {public static void doSomething() {// 静态方法中获取BeanEmailService emailService = SpringContextUtils.getBean(EmailService.class);emailService.send("test@example.com", "Hello");}
}
3. 在JUnit测试中使用
@SpringBootTest
public class UserServiceTest {@Testpublic void testGetUser() {// 在测试中获取BeanUserService userService = SpringContextUtils.getBean(UserService.class);User user = userService.getUserById(1L);assertNotNull(user);}
}
实现原理
-
ApplicationContextAware 接口:
- Spring 会在初始化时自动调用
setApplicationContext
方法 - 将 ApplicationContext 注入到工具类的静态变量中
- Spring 会在初始化时自动调用
-
静态方法访问:
- 所有方法都是静态的,方便在任何地方调用
- 内部检查 ApplicationContext 是否已初始化
-
泛型支持:
- 减少显式类型转换,提高代码安全性
- 编译器会检查类型是否匹配
注意事项
-
初始化时机:
- 确保 Spring 容器完全初始化后再使用工具类
- 不要在 Bean 的构造方法中使用,因为此时 Bean 还未完全初始化
-
单元测试:
- 在测试中需要先启动 Spring 上下文
- 可以使用
@SpringBootTest
注解
-
多线程安全:
- ApplicationContext 是线程安全的
- 工具类本身不包含可变状态,也是线程安全的
-
替代方案:
- 在 Spring Boot 中可以直接使用依赖注入
- 这个工具类主要用在无法使用依赖注入的场景
扩展功能
如果需要更多功能,可以扩展以下方法:
/*** 获取当前环境profile*/
public static String[] getActiveProfiles() {checkApplicationContext();return applicationContext.getEnvironment().getActiveProfiles();
}/*** 判断当前是否是指定环境*/
public static boolean isProfileActive(String profile) {checkApplicationContext();String[] activeProfiles = getActiveProfiles();return Arrays.asList(activeProfiles).contains(profile);
}/*** 发布事件*/
public static void publishEvent(Object event) {checkApplicationContext();applicationContext.publishEvent(event);
}
这个 SpringContextUtils 工具类提供了一种简洁的方式来访问 Spring 容器中的 Bean,特别适合在非 Spring 管理的类中获取 Spring Bean 的场景。