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

Spring 獲取 Bean 的五種核心方式全解析

     編輯:Java 相關知識

核心概念:ApplicationContext vs BeanFactory

  • BeanFactory:Spring 核心接口,延遲初始化(首次 getBean 才創建 Bean)。
  • ApplicationContext:繼承 BeanFactory,啟動時即初始化所有單例 Bean,提供國際化、事件發布、資源加載等企業級功能。實際開發 99% 使用 ApplicationContext。

方式一:手動構建 ApplicationContext(獨立應用/測試)

// 從 classpath 載入
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

// 從文件系統絕對路徑載入
ApplicationContext ctx = new FileSystemXmlApplicationContext("/opt/config/app-context.xml");

// 獲取 Bean
UserService service = ctx.getBean("userService", UserService.class);

適用場景:Main 方法啟動、單元測試、批處理程序、非 Web 容器環境。
缺點:每次調用構建上下文極其耗時,嚴禁在高頻調用處使用。


方式二:Web 環境下透過 WebApplicationContextUtils(傳統 Spring MVC)

// 在 Controller/Filter/Interceptor 中
ServletContext sc = request.getServletContext(); // 或 session.getServletContext()
ApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(sc);
UserService service = ctx.getBean(UserService.class);

前置條件:web.xml 配置 ContextLoaderListener:

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

適用場景:非 Spring 管理的類(如 Servlet、Filter、JSP、舊代碼整合)需獲取 Bean。
缺點:強依賴 Servlet API、難以單元測試、每次調用需獲取 ServletContext。


方式三:繼承 ApplicationObjectSupport(框架擴展/工具類)

public class MyHelper extends ApplicationObjectSupport {
    public void doSomething() {
        ApplicationContext ctx = getApplicationContext(); // 父類提供
        UserService service = ctx.getBean(UserService.class);
    }
}

配置:<bean class="com.example.MyHelper"/>
原理:Spring 初始化時調用 setApplicationContext() 注入上下文。
適用場景:工具類、基類、需訪問上下文的輔助組件。


方式四:繼承 WebApplicationObjectSupport(Web 專用工具類)

public class WebHelper extends WebApplicationObjectSupport {
    public void doWebThing(HttpServletRequest req) {
        WebApplicationContext wac = getWebApplicationContext();
        // 可直接訪問 ServletContext
        ServletContext sc = wac.getServletContext();
    }
}

差異:返回 WebApplicationContext,可訪問 ServletContext、主題解析器等 Web 特有功能。


方式五:實作 ApplicationContextAware(最推薦的通用方案)

@Component
public class SpringContextHolder implements ApplicationContextAware {
    private static ApplicationContext context;
    
    @Override
    public void setApplicationContext(ApplicationContext ctx) throws BeansException {
        context = ctx;
    }
    
    // 靜態獲取,任意處調用
    public static  T getBean(String name, Class clazz) {
        return context.getBean(name, clazz);
    }
    public static  T getBean(Class clazz) {
        return context.getBean(clazz);
    }
    public static ApplicationContext getContext() { return context; }
}

優勢:

  • 靜態方法調用,零依賴注入,任意類(包括非 Spring 管理類)可用。
  • 單例模式,全局唯一上下文引用。
  • 支援按名稱/類型獲取、列表獲取。

注意:必須掃描到該 Bean(@Component 或 XML 配置),否則 context 為 null。


現代 Spring Boot 最佳實踐

@SpringBootApplication
public class App {
    public static void main(String[] args) {
        ConfigurableApplicationContext ctx = SpringApplication.run(App.class, args);
        // 程式化獲取
        UserService service = ctx.getBean(UserService.class);
    }
}

// 組件中注入(標準方式,非手動獲取)
@Service
public class OrderService {
    private final UserService userService; // 建構子注入
    public OrderService(UserService userService) { this.userService = userService; }
}

選型決策表

場景推薦方式關鍵點
Main 方法/批處理/測試方式一手動構建上下文
Servlet/Filter/JSP 非 Spring 類方式二WebApplicationContextUtils
通用工具類/基類/框架擴展方式三/四繼承 *ObjectSupport
任意非 Spring 類靜態獲取(最通用)方式五ApplicationContextAware + 靜態 holder
Spring 管理的 Service/Component/Controller建構子/Setter/@Autowired 注入首選依賴注入,避免手動獲取

核心原則

  1. 優先使用依賴注入(@Autowired/建構子注入),手動獲取是「違背 IoC」的補救手段。
  2. 手動獲取僅用於邊界整合層(舊系統、非 Spring 類、動態腳本)。
  3. ApplicationContextAware 靜態 Holder 是通用性最強、副作用最小的方案。
  4. 嚴禁在高頻業務邏輯中重複構建 ClassPathXmlApplicationContext。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved