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. 核心功能

  • 获取 ApplicationContextgetApplicationContext()
  • 通过名称获取 BeangetBean(String name)
  • 通过类型获取 BeangetBean(Class<T> clazz)
  • 通过名称和类型获取 BeangetBean(String name, Class<T> clazz)
  • 获取指定类型的所有 BeangetBeansOfType(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("[email protected]", "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 的场景。

相关推荐
元亓亓亓13 分钟前
java后端开发day35--集合进阶(四)--双列集合:Map&HashMap&TreeMap
java·开发语言
全栈老李技术面试38 分钟前
【高频考点精讲】JavaScript中的访问者模式:从AST解析到数据转换的艺术
开发语言·前端·javascript·面试·html·访问者模式
广龙宇1 小时前
【一起学Rust】使用Thunk工具链实现Rust应用对Windows XP/7的兼容性适配实战
开发语言·windows·rust
jerry2011081 小时前
R语言之rjava版本不匹配解决方法
开发语言·r语言
拓端研究室TRL1 小时前
PYTHON用几何布朗运动模型和蒙特卡罗MONTE CARLO随机过程模拟股票价格可视化分析耐克NKE股价时间序列数据
开发语言·python
独立开阀者_FwtCoder1 小时前
狂收 33k+ star!全网精选的 MCP 一网打尽!!
java·前端·javascript
再路上12161 小时前
direct_visual_lidar_calibration iridescence库问题
java·服务器·数据库
无畏烧风1 小时前
[Qt]双击事件导致的问题
开发语言·qt
CheungChunChiu1 小时前
Qt 容器类使用指南
linux·开发语言·c++·qt·容器
小王努力学编程2 小时前
美团2024年春招第一场笔试 C++
开发语言·数据结构·c++·学习·算法