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

Spring 屬性注入全解析:基本類型、集合、日期與父 Bean 抽取

     編輯:Java 相關知識

前言

Spring IoC 容器的核心能力之一是靈活的屬性注入(Dependency Injection)。本文通過完整示例,系統講解 基本類型、數組、List、Set、Map、java.util.Date 等各類屬性的 XML 注入方式,並展示 父 Bean 抽取公共配置 以及 自定義 PropertyEditor 實現日期字符串轉換 的進階技巧。

領域模型定義

1. 基礎屬性載體 Bean11

package com.jadyer.model;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class Bean11 {
    private Integer intValue;
    private String strValue;
    private String[] arrayValue;
    private List<String> listValue;
    private Set<String> setValue;
    private Map<String, String> mapValue;
    private Date dateValue;
    // 省略 getter/setter
}

2. 關聯對象 Bean22 / Bean33 / Bean44 / Bean55

public class Bean22 {
    private Bean33 bean33;
    private Bean44 bean44;  // 對應 setter setBean44()
    private Bean55 bean55;
    // getter/setter
}

public class Bean33 { private Integer id; private String name; private String sex; }
public class Bean44 { private Integer id; private String name; private String sex; private Integer age; }
public class Bean55 { private String password; }

XML 配置詳解

1. 主配置:applicationContext-beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="https://www.springframework.org/schema/beans"
       xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="https://www.springframework.org/schema/beans
                           https://www.springframework.org/schema/beans/spring-beans.xsd"
       default-lazy-init="true">

    <!-- 基礎類型與集合注入 -->
    <bean id="bean11" class="com.jadyer.model.Bean11">
        <property name="intValue" value="123"/> <!-- 自動轉型 -->
        <property name="strValue" value="Hello_Spring"/>
        
        <property name="arrayValue">
            <list><value>array11</value><value>array22</value></list>
        </property>
        
        <property name="listValue">
            <list><value>list11</value><value>list22</value></list>
        </property>
        
        <property name="setValue">
            <set><value>set11</value><value>set22</value></set>
        </property>
        
        <property name="mapValue">
            <map>
                <entry key="key11" value="value11"/>
                <entry key="key22" value="value22"/>
            </map>
        </property>
        
        <!-- 日期注入:格式需與 PropertyEditor 一致 -->
        <property name="dateValue" value="2010年06月04日"/>
    </bean>

    <!-- 關聯對象注入 -->
    <bean id="bean22" class="com.jadyer.model.Bean22">
        <property name="bean33" ref="bean33"/>
        <property name="bean44" ref="bean44"/> <!-- 對應 setBean44() -->
        <property name="bean55" ref="bean55"/>
    </bean>

    <bean id="bean55" class="com.jadyer.model.Bean55">
        <property name="password" value="123"/>
    </bean>
</beans>

2. 公共配置抽取:applicationContext-common.xml

<beans ...>
    <!-- 定義抽象父 Bean,abstract="true" 表示不實例化 -->
    <bean id="abstractBean" abstract="true">
        <property name="id" value="2"/>
        <property name="name" value="張起靈"/>
        <property name="sex" value="男"/>
    </bean>

    <!-- 子 Bean 繼承父 Bean 配置,僅覆蓋差異屬性 -->
    <bean id="bean33" class="com.jadyer.model.Bean33" parent="abstractBean"/>
    
    <bean id="bean44" class="com.jadyer.model.Bean44" parent="abstractBean">
        <property name="age" value="26"/>
    </bean>
</beans>

優勢:消除重複配置,修改公共屬性只需改一處;子 Bean 仍可覆蓋任意屬性。

3. 自定義日期編輯器:applicationContext-editor.xml

<beans ...>
    <!-- 1. 定義編輯器 Bean -->
    <bean id="utilDatePropertyEditor" class="com.jadyer.util.UtilDatePropertyEditor">
        <property name="pattern" value="yyyy年MM月dd日"/>
    </bean>

    <!-- 2. 向容器註冊:java.util.Date 類型統一使用該編輯器 -->
    <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
        <property name="customEditors">
            <map>
                <entry key="java.util.Date" value-ref="utilDatePropertyEditor"/>
            </map>
        </property>
    </bean>
</beans>

4. 日期編輯器實現

package com.jadyer.util;

import java.beans.PropertyEditorSupport;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class UtilDatePropertyEditor extends PropertyEditorSupport {
    private String pattern;

    public void setPattern(String pattern) { this.pattern = pattern; }

    @Override
    public void setAsText(String text) throws IllegalArgumentException {
        try {
            Date date = new SimpleDateFormat(pattern).parse(text);
            setValue(date);  // 關鍵:將轉換後的 Date 對象設置進去
        } catch (ParseException e) {
            throw new IllegalArgumentException("日期解析失敗: " + text, e);
        }
    }
}

原理:Spring 容器啟動時,遇到 <property name="dateValue" value="..."/>,會查找針對 java.util.Date 的 PropertyEditor,調用 setAsText() 將字符串轉為 Date 對象後再注入。

延遲初始化說明

主配置中的 default-lazy-init="true" 使所有 Bean 採用「按需創建」模式:

  • 無該屬性:容器啟動時立即實例化所有單例 Bean,適合早期發現配置錯誤。
  • 有該屬性:首次 getBean() 時才創建,啟動更快,但錯誤發現延後。
  • 也可在單個 <bean lazy-init="true"> 精確控制。

單元測試驗證

package com.jadyer.junit;

import junit.framework.TestCase;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.jadyer.model.Bean11;
import com.jadyer.model.Bean22;

public class PropertyInjectionTest extends TestCase {
    private ApplicationContext factory;

    @Override
    protected void setUp() {
        // 通配符加載多個配置文件,合並為一個上下文
        factory = new ClassPathXmlApplicationContext("applicationContext-*.xml");
    }

    public void testInjection11() {
        Bean11 bean = (Bean11) factory.getBean("bean11");
        System.out.println("intValue: " + bean.getIntValue());
        System.out.println("strValue: " + bean.getStrValue());
        System.out.println("arrayValue: " + java.util.Arrays.toString(bean.getArrayValue()));
        System.out.println("listValue: " + bean.getListValue());
        System.out.println("setValue: " + bean.getSetValue());
        System.out.println("mapValue: " + bean.getMapValue());
        System.out.println("dateValue: " + bean.getDateValue());  // 輸出標準 Date 格式
    }

    public void testInjection22() {
        Bean22 bean = (Bean22) factory.getBean("bean22");
        System.out.println("bean33: " + bean.getBean33().getName());
        System.out.println("bean44 age: " + bean.getBean44().getAge());
        System.out.println("bean55 pwd: " + bean.getBean55().getPassword());
    }
}

核心知識點總結

場景XML 寫法關鍵點
基本類型<property name="x" value="123"/>Spring 內置編輯器自動轉型
數組 / List<list><value>...</value></list><list> 同時適用於數組與 List
Set<set><value>...</value></set>自動去重
Map<map><entry key="k" value="v"/></map>Key/Value 均可為引用
日期類型<property name="d" value="2010年06月04日"/>需自定義 PropertyEditor + CustomEditorConfigurer
引用對象<property name="obj" ref="beanId"/>ref 指向目標 Bean 的 id/name
公共配置復用abstract="true" + parent="..."父 Bean 不實例化,子 Bean 繼承並可覆蓋

最佳實踐建議

  1. 優先使用構造器注入 強制依賴,@Autowired 配合構造器最清晰;Setter 注入用於可選依賴。
  2. 集合注入優先用 <util:list> 等命名空間(Spring 2.5+),語義更清晰,支持跨文件引用。
  3. 日期類型建議改用 Java 8 LocalDate/LocalDateTime,Spring 3.4+ 內置支持,無需自定義編輯器。
  4. 生產環境慎用 default-lazy-init="true",啟動階段暴露配置錯誤更安全。

結語

Spring 屬性注入機制強大且靈活,掌握基本類型、集合、日期、父 Bean 抽取、自定義編輯器這五大核心場景,足以應對 95% 以上的業務建模需求。隨著 Spring 版本演進,注解驅動(@Value、@ConfigurationProperties)逐漸取代 XML,但理解底層 XML 機制對排查疑難雜症、維護舊項目仍具不可替代的價值。

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