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

Spring Bean 管理核心完整指南:依賴注入六大模式、集合注入、自動裝配與生命週期

     編輯:Java 相關知識

前言

Spring 容器的核心職責是Bean 生命週期管理與依賴注入 (DI)。掌握 setter、constructor、field 三大注入方式、自動裝配四種模式、集合類型注入、依賴檢查、初始化/銷毀回調,是 Spring 開發者的必修課。本文系統性整理 Spring Bean 管理完整知識體系 (基於 Spring 5.x / Spring Boot 2.x+)。

依賴注入三大核心方式

1. Setter 注入 (傳統 XML 風格)

<bean id="helloBean" class="com.example.HelloBean">
    <property name="message" value="Hello Setter!"></property>
    <property name="count" value="100"></property>
</bean>
public class HelloBean {
    private String message;
    private int count;
    // 必須提供 setter
    public void setMessage(String message) { this.message = message; }
    public void setCount(int count) { this.count = count; }
}

特點:可讀性好、支援選填依賴、可重新綁定、需無參建構子

2. 建構子注入 (推薦:不可變性、強制依賴)

<bean id="helloBean" class="com.example.HelloBean">
    <constructor-arg index="0" value="Hello Constructor!"></constructor-arg>
    <constructor-arg index="1" value="200"></constructor-arg>
</bean>
public class HelloBean {
    private final String message; // final 不可變
    private final int count;
    
    public HelloBean(String message, int count) {
        this.message = message;
        this.count = count;
    }
    // 無 setter 也能注入
}

特點:不可變物件、強制依賴、循環依賴早期發現、易於單元測試 (無 Spring 也能 new)

3. 欄位注入 (Spring Boot 常見,僅限框架內部)

@Component
public class HelloBean {
    @Autowired // 或 @Value("${config.value}")
    private String message;
    
    @Autowired
    private OtherBean otherBean;
}

⚠️ 缺點:無法在無 Spring 環境下單元測試、隱藏依賴關係、不可用於 final 欄位、循環依賴難發現

✅ 建議:優先使用建構子注入,必要時輔以 Setter 注入 (選填依賴)

自動裝配四種模式

模式XML 屬性匹配規則適用場景
byNameautowire="byName"屬性名 = Bean ID命名規範嚴謹的專案
byTypeautowire="byType"屬性類型 = Bean 類型 (唯一)單一實作類、介面唯一實作
constructorautowire="constructor"建構子參數類型匹配建構子注入場景
autodetectautowire="autodetect"先試 constructor 再試 byType遺專案遷移

現代註解替代:@Autowired + @Qualifier

@Autowired
@Qualifier("specialDataSource") // byName 精確指定
private DataSource dataSource;

@Autowired // byType (若多個實作需加 @Qualifier)
private UserService userService;

集合類型注入完整範例

<bean id="collectionBean" class="com.example.CollectionBean">
    <!-- List 注入 -->
    <property name="stringList">
        <list>
            <value>Item1</value>
            <value>Item2</value>
            <ref bean="otherBean"/>
        </list>
    </property>
    
    <!-- Set 注入 (去重) -->
    <property name="stringSet">
        <set>
            <value>A</value>
            <value>B</value>
            <value>A</value> <!-- 重複會被忽略 -->
        </set>
    </property>
    
    <!-- Map 注入 -->
    <property name="configMap">
        <map>
            <entry key="url" value="jdbc:mysql://..."/>
            <entry key="poolSize" value="20"/>
            <entry key="dataSource" value-ref="dataSource"/>
        </map>
    </property>
    
    <!-- Properties 注入 -->
    <property name="props">
        <props>
            <prop key="hibernate.dialect">MySQLDialect</prop>
            <prop key="hibernate.show_sql">true</prop>
        </props>
    </property>
    
    <!-- 數組注入 -->
    <property name="stringArray">
        <array>
            <value>arr1</value>
            <value>arr2</value>
        </array>
    </property>
</bean>

對應 Java 類別

public class CollectionBean {
    private List stringList;
    private Set stringSet;
    private Map configMap;
    private Properties props;
    private String[] stringArray;
    // Getter/Setter...
}

依賴檢查

<bean id="helloBean" class="com.example.HelloBean" 
      dependency-check="objects"> <!-- 可選:simple, objects, all, none(default) -->
    <property name="message" value="Hello"/>
</bean>
模式檢查範圍
none不檢查 (預設)
simple基本類型、String、基本類型包裝類
objects物件引用類型 (協作 Bean)
all所有屬性

現代替代:@Required (已棄用) → 建構子注入天然強制依賴 + @NonNull (JSR-305) + 單元測試

Bean 生命週期與回調

實例化 → 屬性填充 → 初始化 → 使用中 → 銷毀
   │           │          │
   │           │          ├─ @PostConstruct / init-method
   │           │          ├─ InitializingBean.afterPropertiesSet()
   │           │          └─ BeanPostProcessor.postProcessBefore/AfterInitialization()
   │           │
   │           └─ @Autowired / @Value / XML property
   │
   └─ 建構子 / 工廠方法

初始化回調三種方式 (優先序遞減)

  1. @PostConstruct (JSR-250,推薦,標準化)
  2. implements InitializingBean → afterPropertiesSet() (Spring 耦合)
  3. XML init-method="init" / Java Config @Bean(initMethod="init")

銷毀回調三種方式

  1. @PreDestroy (JSR-250,推薦)
  2. implements DisposableBean → destroy()
  3. XML destroy-method="cleanup" / @Bean(destroyMethod="cleanup")

完整範例

@Component
public class LifecycleBean implements InitializingBean, DisposableBean {
    
    @PostConstruct
    public void init() {
        System.out.println("1. @PostConstruct 初始化");
    }
    
    @Override
    public void afterPropertiesSet() {
        System.out.println("2. InitializingBean.afterPropertiesSet()");
    }
    
    @PreDestroy
    public void cleanup() {
        System.out.println("1. @PreDestroy 銷毀");
    }
    
    @Override
    public void destroy() {
        System.out.println("2. DisposableBean.destroy()");
    }
}

Bean 作用域

@Component
@Scope("prototype") // 或 ConfigurableBeanFactory.SCOPE_PROTOTYPE
public class PrototypeBean { }

循環依賴解決方案

// A 需 B,B 需 A (Setter/Field 注入會觸發)
@Component
public class A {
    @Autowired @Lazy // 延遲注入:注入代理物件,首次使用時才建立真實 B
    private B b;
}

@Component
public class B {
    @Autowired
    private A a; // 建構子注入無法解決循環依賴 (除非一方用 @Lazy + Provider)
}

根治:重構設計、引入中介者、事件驅動、或改用建構子注入 + @Lazy + ObjectProvider

總結:現代 Spring Bean 管理最佳實務

  1. 優先建構子注入,配合 final 確保不可變性
  2. 使用 @Component + @Autowired 替代 XML
  3. 集合注入用 @Value("#{'${list.values}'.split(',')}") 或 @ConfigurationProperties
  4. 生命週期用 @PostConstruct/@PreDestroy
  5. 作用域預設 singleton,有狀態 Bean 用 prototype/request
  6. 避免循環依賴,出現時重構而非 @Lazy 掩蓋
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
作用域說明Web 環境
singleton容器中單一實例 (預設)✓
prototype每次請求建立新實例✓
request每個 HTTP 請求一個實例僅 Web
session每個 HTTP Session 一個實例僅 Web
application每個 ServletContext 一個實例僅 Web
websocket每個 WebSocket 會話一個實例僅 Web