Spring 核心是 IoC 容器管理 Bean 生命周期與依賴關係。在 XML 配置元數據模式下(雖然現代項目多用註解,但維護老項目、理解原理仍需掌握),除常見的 <constructor-arg>、<property> 外,Spring 還提供 **FactoryBean 機制** 實現「方法返回值注入」「字段值注入」「任意靜態方法調用」等高級注入。本文系統梳理 7 種姿勢。
| 方式 | XML 元素 | 底層調用 | 適用場景 |
|---|---|---|---|
| 構造器注入 | <constructor-arg> | 有參構造器 | 強依賴、不可變對象 |
| Setter 注入 | <property> | setXxx() | 可選依賴、可變對象 |
Spring 內建三個 FactoryBean,讓 XML 能表達「調用方法/讀取字段/調用靜態方法」並將結果作為 Bean 注入:
<!-- 調用實例方法 -->
<bean id="valueGenerator" class="com.example.ValueGenerator"/>
<bean id="dynamicValue" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject" ref="valueGenerator"/>
<property name="targetMethod" value="generate"/>
<property name="arguments">
<list><value>param1</value></list>
</property>
</bean>
<!-- 調用靜態方法(簡寫) -->
<bean id="systemProps" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="staticMethod" value="java.lang.System.getProperty"/>
<property name="arguments">
<list><value>java.version</value></list>
</property>
</bean>
<!-- 將方法返回值直接注入其他 Bean -->
<bean id="consumer" class="com.example.Consumer">
<property name="config" ref="dynamicValue"/>
</bean>
<!-- 讀取靜態常量 -->
<bean id="serializableLevel" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
<property name="staticField" value="java.sql.Connection.TRANSACTION_SERIALIZABLE"/>
</bean>
<!-- 讀取實例字段(需先有目標 Bean) -->
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource" .../>
<bean id="poolSize" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
<property name="targetObject" ref="dataSource"/>
<property name="targetField" value="maximumPoolSize"/>
</bean>
<bean id="orderService" class="com.example.OrderService">
<property name="userService" ref="userService"/>
</bean>
<!-- 獲取 orderService.userService.userDao.dataSource.url -->
<bean id="dbUrl" class="org.springframework.beans.factory.config.PropertyPathFactoryBean">
<property name="targetBeanName" value="orderService"/>
<property name="propertyPath" value="userService.userDao.dataSource.url"/>
</bean>
<!-- 簡寫:Bean id 即屬性路徑 -->
<bean id="orderService.userService.userDao.dataSource.url"
class="org.springframework.beans.factory.config.PropertyPathFactoryBean"/>
| FactoryBean | 核心屬性 | 典型用例 | 是否支持參數 |
|---|---|---|---|
| MethodInvokingFactoryBean | targetObject/targetClass, targetMethod, arguments, staticMethod | 調用工具類靜態方法、實例方法獲取配置值 | 是 |
| FieldRetrievingFactoryBean | staticField / (targetObject + targetField) | 讀取常量、單例對象的公共字段 | 否 |
| PropertyPathFactoryBean | targetBeanName, propertyPath | 深層屬性鏈導航、將內部對象暴露為獨立 Bean | 否 |
<bean id="dbProps" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="staticMethod" value="java.lang.System.getProperties"/>
</bean>
<bean id="jdbcUrl" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject" ref="dbProps"/>
<property name="targetMethod" value="getProperty"/>
<property name="arguments">
<list><value>jdbc.url</value></list>
</property>
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource">
<property name="url" ref="jdbcUrl"/>
<property name="username" value="${jdbc.user}"/>
<property name="password" value="${jdbc.pass}"/>
</bean>
<property name="lazy-init" value="true"/> 或重構。Object,注入目標若為基本類型/String,Spring 自動轉換;複雜類型需確保返回類型匹配。<property name="singleton" value="false"/>(僅 MethodInvokingFactoryBean 支持)。@Value("#{systemProperties['jdbc.url']}")、@Autowired + @Qualifier、@Bean 方法體內直接調用,XML FactoryBean 僅用於維護舊系統。Spring XML 配置通過 **三大 FactoryBean** 將「方法調用、字段讀取、屬性路徑導航」納入依賴注入體系,極大擴展了聲明式裝配能力。理解這 7 種注入姿勢(2 基礎 + 3 FactoryBean + 2 組合變體),能靈活應對老項目中各種非標準裝配需求,也是深入理解 Spring 容器擴展機制的關鍵一課。