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.pswp.cn/diannao/80142.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/80142.shtml
英文地址,請注明出處:http://en.pswp.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…