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

Spring 容器中獲取 Bean 的三種方式:ServletContext、Listener 與通用靜態工具類 SpringContextHolder

     編輯:Java 綜合教學

Spring 容器中獲取 Bean 的三種方式:ServletContext、Listener 與通用靜態工具類 SpringContextHolder

在非 Spring 管理的類(如工具類、JMS 監聽器、定時任務、舊代碼集成)中獲取 Spring Bean,是常見需求。本文對比三種方案,強力推薦第三種通用靜態持有者模式,一次配置,全局隨處可用。

方式一:ServletContext 獲取(DispatcherServlet 場景)

適用於 Spring MVC DispatcherServlet 初始化的上下文。

// web.xml
<servlet>
    <servlet-name>springMVC</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath*:/springMVC.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

Spring 容器存放在 ServletContext 的 key 為:

org.springframework.web.servlet.FrameworkServlet.CONTEXT.springMVC
// 其中 springMVC 為 servlet-name 值

獲取代碼:

ServletContext sc = ...; // 從 request/session/servletContext 獲取
WebApplicationContext ctx = (WebApplicationContext) sc.getAttribute(
    "org.springframework.web.servlet.FrameworkServlet.CONTEXT.springMVC");
MyBean bean = ctx.getBean(MyBean.class);

缺點:強耦合 Servlet API、key 魔法字符串、僅限 Spring MVC 場景。

方式二:ContextLoaderListener 獲取(傳統 Spring 場景)

// web.xml
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

獲取代碼:

ServletContext context = getServletContext();
WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(context);
MyBean bean = ctx.getBean(MyBean.class);

缺點:仍依賴 ServletContext、需在 Web 環境下。

方式三:通用靜態工具類 SpringContextHolder ⭐ 推薦

實現 ApplicationContextAware,在容器啟動時自動注入 ApplicationContext 到靜態變量,提供靜態 getBean() 方法,完全脫離 Web 環境,任意類隨時調用。

1. 定義工具類

import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class SpringContextHolder implements ApplicationContextAware {
    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext ctx) {
        SpringContextHolder.applicationContext = ctx;
    }

    public static ApplicationContext getApplicationContext() {
        checkApplicationContext();
        return applicationContext;
    }

    @SuppressWarnings("unchecked")
    public static  T getBean(String name) {
        checkApplicationContext();
        return (T) applicationContext.getBean(name);
    }

    @SuppressWarnings("unchecked")
    public static  T getBean(Class clazz) {
        checkApplicationContext();
        return (T) applicationContext.getBeansOfType(clazz);
    }

    public static void cleanApplicationContext() {
        applicationContext = null;
    }

    private static void checkApplicationContext() {
        if (applicationContext == null) {
            throw new IllegalStateException(
                "applicaitonContext未注入,請在applicationContext.xml中定義SpringContextHolder");
        }
    }
}

2. Spring 配置註冊(關鍵:lazy-init="false" 保證啟動即初始化)

<!-- 用於持有ApplicationContext,可使用SpringContextHolder.getBean('xxxx')靜態方法得到spring bean對象 -->
<bean class="com.xxxxx.SpringContextHolder" lazy-init="false" />

3. 任意處調用

// 按名稱獲取
UserService userService = SpringContextHolder.getBean("userService");

// 按類型獲取(單例 Bean)
UserService userService = SpringContextHolder.getBean(UserService.class);

方案對比總結

維度方式一 ServletContext方式二 Listener方式三 SpringContextHolder
適用場景Spring MVC傳統 Spring通用(含非 Web、定時任務、測試)
依賴環境Web + Servlet APIWeb + Servlet API無(純 Spring)
調用便捷度需獲取 ServletContext需獲取 ServletContext靜態方法一行代碼
線程安全是是是(靜態變量寫一次讀多次)
推薦指數⭐⭐⭐⭐⭐⭐⭐⭐⭐

注意事項

  • lazy-init="false" 必須設置,否則 Bean 延遲初始化導致 setApplicationContext 不執行,靜態變量為 null。
  • 單元測試中需手動調用 SpringContextHolder.cleanApplicationContext() 避免上下文殘留污染。
  • 集群/分布式環境下,ApplicationContext 非共享,每個 JVM 獨立持有,無跨節點影響。
  • 若項目使用 Spring Boot,直接注入 ApplicationContext 或用 @Autowired 更簡潔,無需此工具類。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved