Java 实现SpringContextUtils工具类,手动获取Bean

SpringContextUtils 工具类实现

下面是一个完整的 Spring 上下文工具类实现,用于从 Spring 容器中获取 Bean。这个工具类考虑了线程安全、性能优化和易用性,并提供了多种获取 Bean 的方式。

完整实现代码

java 复制代码
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
     */
    @Override
    public 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. 基本使用

java 复制代码
// 获取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

java 复制代码
// 获取所有实现UserService接口的Bean
Map<String, UserService> userServices = SpringContextUtils.getBeansOfType(UserService.class);

userServices.forEach((name, service) -> {
    System.out.println("Bean名称: " + name + ", 实例: " + service);
});

3. 获取环境配置

java 复制代码
// 获取application.properties/yml中的配置
String appName = SpringContextUtils.getProperty("spring.application.name");
String serverPort = SpringContextUtils.getProperty("server.port");

高级用法

1. 在非Spring管理的类中使用

java 复制代码
public class NonSpringClass {
    public void someMethod() {
        // 获取Spring容器中的Bean
        UserRepository repository = SpringContextUtils.getBean(UserRepository.class);
        repository.save(new User());
    }
}

2. 在静态方法中使用

java 复制代码
public class UtilityClass {
    public static void doSomething() {
        // 静态方法中获取Bean
        EmailService emailService = SpringContextUtils.getBean(EmailService.class);
        emailService.send("test@example.com", "Hello");
    }
}

3. 在JUnit测试中使用

java 复制代码
@SpringBootTest
public class UserServiceTest {
    @Test
    public void testGetUser() {
        // 在测试中获取Bean
        UserService userService = SpringContextUtils.getBean(UserService.class);
        User user = userService.getUserById(1L);
        assertNotNull(user);
    }
}

实现原理

  1. ApplicationContextAware 接口:

    • Spring 会在初始化时自动调用 setApplicationContext 方法
    • 将 ApplicationContext 注入到工具类的静态变量中
  2. 静态方法访问:

    • 所有方法都是静态的,方便在任何地方调用
    • 内部检查 ApplicationContext 是否已初始化
  3. 泛型支持:

    • 减少显式类型转换,提高代码安全性
    • 编译器会检查类型是否匹配

注意事项

  1. 初始化时机:

    • 确保 Spring 容器完全初始化后再使用工具类
    • 不要在 Bean 的构造方法中使用,因为此时 Bean 还未完全初始化
  2. 单元测试:

    • 在测试中需要先启动 Spring 上下文
    • 可以使用 @SpringBootTest 注解
  3. 多线程安全:

    • ApplicationContext 是线程安全的
    • 工具类本身不包含可变状态,也是线程安全的
  4. 替代方案:

    • 在 Spring Boot 中可以直接使用依赖注入
    • 这个工具类主要用在无法使用依赖注入的场景

扩展功能

如果需要更多功能,可以扩展以下方法:

java 复制代码
/**
 * 获取当前环境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 的场景。

相关推荐
Wx-bishekaifayuan3 小时前
springboot线上中医药养生平台管理系统36753-计算机课程设计、毕业设计
java·spring boot·后端·spring·课程设计·express·旅游
Wx-bishekaifayuan3 小时前
springboot大学生就业平台47691-计算机课程设计、毕业设计
java·spring boot·后端·elasticsearch·课程设计·express·旅游
zjxtxdy3 小时前
R语言数据统计入门
开发语言·r语言
汤姆yu4 小时前
基于springboot+vue的企业OA办公系统
java·spring boot·后端·oa办公
南归北隐4 小时前
Spring AI Alibaba Graph框架实现RAG私有知识库问答
java·后端·spring·spring ai·java rag实现
cleble4 小时前
怎么用用 PowerShell 下载文件
开发语言·php
w2sfot4 小时前
AI时代,JS加密还有效吗?
开发语言·前端·javascript
yujunl4 小时前
U9C WSS项目的学习成果
开发语言
从琳开始9894 小时前
[JavaEE]多线程初阶(下篇)------多线程案例(单例模式,阻塞队列,线程池,定时器)
java·单例模式·java-ee
乌暮4 小时前
# Spring 入门与 Spring MVC 实战指南:从零理解 IoC 到 RESTful 图书管理
java·开发语言·后端·学习·spring·mvc·restful