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

Spring 進階:用 FactoryBean 實現動態配置,讓 XML 活起來

     編輯:Java 相關知識

痛點:Spring XML 看似「靜態」

許多開發者認為 Spring 配置只能靜態設置參數 (數據源、定時器等),實則 Spring 提供 FactoryBean 機制優雅解決動態配置需求。

FactoryBean 接口核心契約

public interface FactoryBean {
    Object getObject() throws Exception;      // 返回管理的對象實例 (單例/原型)
    Class getObjectType();                    // 返回對象類型,供自動裝配檢查
    boolean isSingleton();                    // 是否單例 (true=getObject() 返回同一引用)
}

關鍵語義:實現 FactoryBean 的 Bean 本身不作為最終 Bean 使用,容器調用其 getObject() 返回的對象才是真正注入的 Bean。框架內大量使用 (AOP ProxyFactoryBean、JNDI JndiObjectFactoryBean、Hibernate LocalSessionFactoryBean)。

實戰:動態數據源配置

場景:數據庫連接參數存放於外部配置中心/加密文件/環境變量,啟動時動態讀取組裝 BasicDataSource。

自定義 FactoryBean 實現

public class BasicDataSourceFactoryBean implements FactoryBean {
    public Object getObject() throws Exception {
        BasicDataSource dataSource = new BasicDataSource();
        // 1. 從外部源讀取配置 (配置中心、環境變量、加密文件、Consul/Etcd 等)
        // 2. 設置屬性
        dataSource.setDriverClassName(...);
        dataSource.setUrl(...);
        dataSource.setUsername(...);
        dataSource.setPassword(...);
        dataSource.setInitialSize(...);
        // ... 其他連接池參數
        return dataSource;
    }
    public Class getObjectType() {
        return BasicDataSource.class;
    }
    public boolean isSingleton() {
        return true;  // 數據源通常為單例
    }
}

Spring XML 聲明

<bean id="dataSource" class="com.example.BasicDataSourceFactoryBean">
    <!-- 可注入配置源引用:Properties、Environment、ConfigClient 等 -->
    <property name="configLocation" value="classpath:db.properties"/>
    <property name="decryptor" ref="passwordDecryptor"/>
</bean>

容器啟動時調用 getObject(),獲得動態構建的 DataSource,其他 Bean 引用 dataSource 時拿到的是真實連接池而非 FactoryBean 本身。

擴展場景

  • 環境區分:同一 FactoryBean 根據 Profile (dev/test/prod) 讀取不同配置源
  • 敏感信息解密:注入解密器,getObject() 內解密密碼後設置
  • 條件化創建:根據運行參數決定返回實現類型 (如切換 HikariCP/Druid/DBCP)
  • 延遲初始化:lazy-init="true" 配合 FactoryBean 實現真正的按需創建

原理解析

  1. 容器解析到 class="...FactoryBean" 的 Bean 定義
  2. 實例化 FactoryBean 本身 (調用構造器、注入屬性)
  3. 若非懶加載,調用 getObject() 獲取真實對象
  4. 將真實對象註冊到單例緩存 (若 isSingleton()=true)
  5. 其他地方 @Autowired DataSource 或 <ref bean="dataSource"/> 獲得真實對象

這正是 JndiObjectFactoryBean、LocalSessionFactoryBean 等框架內建組件的工作原理。

最佳實踐提醒

  • getObjectType() 務必正確返回類型,否則自動裝配 (byType) 會忽略該 Bean
  • isSingleton() 誠實聲明:若返回 true 但每次 getObject() 創建新實例,會導致緩存不一致
  • FactoryBean 本身通常定義為 singleton (默認),getObject() 返回的對象單例狀態由 isSingleton() 決定
  • 異常處理:getObject() 拋出異常會被包裝為 BeanCreationException,上層可捕獲處理

結語

FactoryBean 是 Spring 「配置即代碼」能力的核心擴展點。善用它,XML 配置不再是靜態聲明,而是動態對象工廠的入口,讓 Spring 配置真正「活」起來。

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