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

  • 获取 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. 基本使用

// 获取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);}
}

实现原理

  1. ApplicationContextAware 接口

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

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

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

注意事项

  1. 初始化时机

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

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

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/80142.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于 Vue 2 开发的分页卡片列表组件(带懒加载和点击事件)

功能目标&#xff1a; CardList.vue 中支持分页&#xff0c;每页显示指定数量的卡片。添加“加载中”动画。支持懒加载&#xff1a;滚动到底部自动加载下一页。点击卡片的事件逻辑由 Card.vue 内部发出&#xff0c;并由 CardList 向上传递。 主页面文件 Home.vue <templat…

【数据结构和算法】6. 哈希表

本文根据 数据结构和算法入门 视频记录 文章目录 1. 哈希表的概念1.1 哈希表的实现方式1.2 哈希函数&#xff08;Hash Function&#xff09;1.3 哈希表支持的操作 2. Java实现 在前几章的学习中&#xff0c;我们已经了解了数组和链表的基本特性&#xff0c;不管是数组还是链表…

【python】如何将文件夹及其子文件夹下的所有word文件汇总导出到一个excel文件里?

根据你的需求,这里提供一套完整的Python解决方案,支持递归遍历子文件夹、提取Word文档内容(段落+表格),并整合到Excel中。以下是代码实现及详细说明: 一个单元格一个word的全部内容 完整代码 # -*- coding: utf-8 -*- import os from docx import Document import pand…

leetcode-位运算

位运算 371. 两整数之和 题目 给你两个整数 a 和 b &#xff0c;不使用 运算符 和 - &#xff0c;计算并返回两整数之和。 示例 1&#xff1a; 输入&#xff1a; a 1, b 2 输出&#xff1a; 3 示例 2&#xff1a; 输入&#xff1a; a 2, b 3 输出&#xff1a; 5 提示&am…

飞帆控件:在编辑模式下额外加载的库

飞帆是一个自由的控件设计平台。在飞帆中&#xff0c;我们可以很方便地创建基于 Vue 2 组件的控件&#xff0c;并使用控件来搭建网页。 他山之石&#xff0c;可以攻玉。在创建控件中&#xff0c;使用 js 、css 依赖库能让我们的控件更强大。 有些时候&#xff0c;在编辑模式下…

GPLT-2025年第十届团体程序设计天梯赛总决赛题解(共计266分)

今天偶然发现天梯赛的代码还保存着&#xff0c;于是决定写下这篇题解&#xff0c;也算是复盘一下了 L1本来是打算写的稳妥点&#xff0c;最后在L1-6又想省时间&#xff0c;又忘记了insert&#xff0c;replace这些方法怎么用&#xff0c;也不想花时间写一个文件测试&#xff0c…

编码转换器

大批量转换编码 可以将整个工程文件夹从GB18030转为UTF-8 使用Qt C制作 项目背景 比较老的工程&#xff0c;尤其是keil嵌入式的工程&#xff0c;其文本文件&#xff08;.c、.cpp、.h、.txt、……&#xff09;编码为gb2312&#xff0c;这为移植维护等带来了不便。现在uit-8用…

STL 核心模块

很好&#xff01;你想深入 STL&#xff08;Standard Template Library&#xff09;和容器算法&#xff0c;是学习 C 非常关键的一步。下面我给你整理一份STL 容器 算法的入门指南&#xff0c;适合从零起步掌握这部分内容。 &#x1f31f; 一、STL 核心模块 STL 分为三大块&am…

2024沈阳区域赛,D - Dot Product Game

题目链接 树状数组求逆序对 #include<bits/stdc.h> using namespace std; using lllong long; typedef pair<int,int>PII; typedef priority_queue<int> upq; typedef priority_queue<int,vector<int>,greater<int>> dpq; const int M99…

简易博客点赞系统实现

简易博客点赞系统 好久没写 Java 了&#xff0c;整个简单的项目进行康复训练。 基于 Spring Boot SSM MySQL Mybatis-Plus Knife4j Swagger 的一个简易博客点赞系统 开源地址&#xff1a;https://github.com/FangMoyu/simple-thumb 功能 登录获取当前登录用户获取博客…

一个既简单又诡异的问题

public class DaYaoGuai {static String s;public static void main(String[] args) {Thread t1 new Thread(){Overridepublic void run() {try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}s"深圳";}};t1.start();Thre…

使用docker在manjaro linux系统上运行windows和ubuntu

因为最近项目必须要使用指定版本的solidworks和maxwell&#xff08;都只能在win系统上使用&#xff09;, 且目前的ubuntu容器是没有桌面的&#xff0c;导致我运行不了一些带图形的ros2功能。无奈之下&#xff0c;决定使用docker-compose写一下配置文件&#xff0c;彻底解决问题…

Elasticsearch中的_source字段讲解

_source 在 Elasticsearch 查询中用于限制返回的字段,类似于 SQL 中的 SELECT 指定列。 代码示例: esSearchResults = es_service.search_documents({"query": {"terms": {"file_id":

【论文阅读20】-CNN-Attention-BiGRU-滑坡预测(2025-03)

这篇论文主要探讨了基于深度学习的滑坡位移预测模型&#xff0c;结合了MT-InSAR&#xff08;多时相合成孔径雷达干涉测量&#xff09;观测数据&#xff0c;提出了一种具有可解释性的滑坡位移预测方法。 [1] Zhou C, Ye M, Xia Z, et al. An interpretable attention-based deep…

C++ 的 IO 流

&#x1f4ac; &#xff1a;如果你在阅读过程中有任何疑问或想要进一步探讨的内容&#xff0c;欢迎在评论区畅所欲言&#xff01;我们一起学习、共同成长~&#xff01; &#x1f44d; &#xff1a;如果你觉得这篇文章还不错&#xff0c;不妨顺手点个赞、加入收藏&#xff0c;并…

spring cloud gateway前面是否必须要有个nginx

在 **"客户端 → Nginx (前置限流) → Spring Cloud Gateway → 微服务(Sentinel 熔断限流)"** 的架构中&#xff0c;**Spring Cloud Gateway 前面并不强制要求必须有 Nginx**&#xff0c;是否需要取决于具体场景。以下是详细分析&#xff1a; 一、必须使用 Nginx 的…

Spark和Hadoop之间的对比和联系

&#xff08;一&#xff09;Spark概述 Spark是一种基于内存的快速、通用、可拓展的大数据分析计算引擎。Hadoop是一个分布式系统基础架构。 1&#xff09;官网地址&#xff1a;Apache Spark™ - Unified Engine for large-scale data analytics 2&#xff09;文档查看地址&…

多线程进阶(Java)

注&#xff1a;此博文为本人学习过程中的笔记 1.常见的锁策略 当我们需要自己实现一把锁时&#xff0c;需要关注锁策略。Java提供的synchronized已经非常好用了&#xff0c;覆盖了绝大多数的使用场景。此处的锁策略并不是和Java强相关的&#xff0c;只要涉及到并发编程&#…

c++STL——stack、queue、priority_queue的模拟实现

文章目录 stack、queue、priority_queue的模拟实现使用部分模拟实现容器适配器deque的介绍原理真实结构deque的迭代器deque的操作deque的优缺点 stack的模拟实现按需实例化queue的模拟实现priority_queue的模拟实现为何引入仿函数代码实现 stack、queue、priority_queue的模拟实…

【深度学习—李宏毅教程笔记】Transformer

目录 一、序列到序列&#xff08;Seq2Seq&#xff09;模型 1、Seq2Seq基本原理 2、Seq2Seq模型的应用 3、Seq2Seq模型还能做什么&#xff1f; 二、Encoder 三、Decoder 1、Decoder 的输入与输出 2、Decoder 的结构 3、Non-autoregressive Decoder 四、Encoder 和 De…