首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 獲取 Spring 容器 Bean 的 5 種核心方法詳解

     編輯:Java 相關知識

概述

在 Spring 框架開發中,大多數情況下我們通過依賴注入(DI)自動裝配 Bean。但在某些非 Spring 管理的類(如工具類、靜態方法、第三方庫回調)中,需要主動從容器獲取 Bean。本文系統總結 5 種主流獲取方式,並針對適用場景、優缺點及注意事項進行深度解析。

方法一:手動初始化 ApplicationContext(獨立應用)

適用於獨立 Java 應用、單元測試或批處理程序,需手動加載配置文件啟動容器。

ApplicationContext ac = new FileSystemXmlApplicationContext("applicationContext.xml");
MyBean bean = ac.getBean("beanId", MyBean.class);
  • 優點:簡單直接,不依賴 Web 容器。
  • 缺點:每次調用可能創建新容器,資源消耗大;生產環境極少如此使用。

方法二:通過 WebApplicationContextUtils(Web 環境標準方式)

利用 ServletContext 獲取 Web 環境下的 WebApplicationContext,是 Web 應用中最常用的非注入獲取方式。

import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.context.WebApplicationContext;
import javax.servlet.ServletContext;

// 方式 1:必須存在,否則拋出異常
WebApplicationContext wac1 = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);

// 方式 2:允許不存在,返回 null
WebApplicationContext wac2 = WebApplicationContextUtils.getWebApplicationContext(servletContext);

MyBean bean = wac1.getBean(MyBean.class);
  • 適用場景:Servlet、Filter、Listener、JSP 標籤類等擁有 ServletContext 的組件。
  • 關鍵差異:getRequiredWebApplicationContext 找不到時拋 IllegalStateException;getWebApplicationContext 返回 null。

方法三:繼承 ApplicationObjectSupport

Spring 提供的便利基類,通過模板方法模式注入 ApplicationContext。

public class MyService extends ApplicationObjectSupport {
    public void doSomething() {
        ApplicationContext ctx = getApplicationContext(); // 父類提供
        MyBean bean = ctx.getBean(MyBean.class);
    }
}
  • 原理:Spring 初始化時調用 setApplicationContext 完成注入。
  • 限制:類必須在 Spring 配置文件中定義為 Bean(<bean class="..."/>),否則 getApplicationContext() 返回 null。

方法四:繼承 WebApplicationObjectSupport

Web 環境專用基類,提供 getWebApplicationContext() 直接獲取 WebApplicationContext,功能同上但針對 Web 場景優化。

方法五:實現 ApplicationContextAware 接口(推薦通用方案)

實現該接口並重寫 setApplicationContext,Spring 容器啟動時自動回調注入。配合單例模式封裝為工具類,使用極其便捷。

最佳實踐:封裝 Spring 工具類

package com.example.util;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

@Component // 自動掃描註冊為 Bean
public class SpringContextHolder implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext ctx) throws BeansException {
        applicationContext = ctx;
    }

    public static <T> T getBean(Class<T> clazz) {
        checkContext();
        return applicationContext.getBean(clazz);
    }

    public static Object getBean(String name) {
        checkContext();
        return applicationContext.getBean(name);
    }

    private static void checkContext() {
        if (applicationContext == null) {
            throw new IllegalStateException("ApplicationContext 未注入,請確認 SpringContextHolder 已被 Spring 管理!");
        }
    }
}

配置註冊(XML 或掃描)

<!-- XML 方式 -->
<bean id="springContextHolder" class="com.example.util.SpringContextHolder"/>

<!-- 或掃描註解 @Component -->

任意處調用

MyService service = SpringContextHolder.getBean(MyService.class);
// 或
MyService service = (MyService) SpringContextHolder.getBean("myService");

關鍵避坑指南

  1. 非 Spring 管理類無效:以上所有「繼承/實現」方式(方法 3-5),該類必須被 Spring 容器管理(掃描註解、XML 定義或手動註冊),否則回調不執行,上下文為 null。
  2. 容器啟動階段不可用:在 ContextLoaderListener 初始化完成前(如構造器、@PostConstruct 早期),ContextLoader.getCurrentWebApplicationContext() 返回 null。
  3. 靜態字段線程安全:工具類靜態字段需考慮並發,建議用 volatile 或雙重檢查鎖(單例模式已隱含)。
  4. 優先使用依賴注入:能用 @Autowired/構造器注入時,絕不手動獲取,保持 IoC 原則。

總結對比表

方法適用環境前置條件推薦指數
手動初始化獨立應用/測試無⭐
WebApplicationContextUtilsWeb 組件持有 ServletContext⭐⭐⭐⭐
ApplicationObjectSupport通用 Bean類被 Spring 管理⭐⭐
WebApplicationObjectSupportWeb Bean類被 Spring 管理⭐⭐
ApplicationContextAware + 工具類全局任意處工具類被 Spring 管理⭐⭐⭐⭐⭐

結語

掌握這 5 種方式,核心在於理解 Spring 容器生命周期與回調機制。實際開發中,**首選依賴注入**;不得已時,推薦「實現 ApplicationContextAware 封裝工具類」,一次配置,全局可用,且代碼乾淨解耦。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved