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 的场景。

相关推荐
一只码代码的章鱼5 分钟前
Spring 的 异常管理的相关注解@ControllerAdvice 和@ExceptionHandler
java·后端·spring
qqxhb10 分钟前
零基础学Java——第十一章:实战项目 - 微服务入门
java·开发语言·spring cloud·微服务
androidwork16 分钟前
Arrow库:函数式编程在Kotlin Android中的深度实践
android·java·kotlin
离别又见离别20 分钟前
java实现根据Velocity批量生成pdf并合成zip压缩包
java·pdf
码农飞哥25 分钟前
互联网大厂Java求职面试实战:Spring Boot到微服务的技术问答解析
java·spring boot·缓存·面试·消息队列·技术栈·microservices
CodeCraft Studio27 分钟前
国产化Word处理控件Spire.Doc教程:通过C# 删除 Word 文档中的超链接
开发语言·c#·word
martian66540 分钟前
麒麟系统下Tomcat部署Java Web程序(WAR包)及全链路问题排查指南
开发语言·tomcat·系统安全
ai.Neo41 分钟前
牛客网NC22012:判断闰年问题详解
开发语言·c++·算法
曼岛_1 小时前
[Java实战]Spring Boot + Netty 实现 TCP 长连接客户端及 RESTful 请求转发(二十六)
java·spring boot·tcp/ip
好吃的肘子1 小时前
ElasticSearch进阶
大数据·开发语言·分布式·算法·elasticsearch·kafka·jenkins