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

Spring 實例化 JavaBean 三種方式完整解析:XML 配置篇

     編輯:Java 相關知識

前言

Spring IoC 容器管理 Bean 生命週期,實例化策略主要有三種。本文以傳統 XML 配置為例,詳細展示每種方式的配置細節、適用場景與底層原理。

方式一:構造器實例化 (最常用、推薦)

原理:容器調用類別的**無參構造器** (或帶參構造器) 建立實例。

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">

    <!-- 1. 無參構造器 (類別必須有 public 無參構造器) -->
    <bean id="userDao" class="com.example.dao.UserDaoImpl" />

    <!-- 2. 帶參構造器注入 -->
    <bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource">
        <constructor-arg name="jdbcUrl" value="jdbc:mysql://localhost:3306/db" />
        <constructor-arg name="username" value="root" />
        <constructor-arg name="password" value="123456" />
    </bean>

    <!-- 3. 索引/類型匹配 (無名參數) -->
    <bean id="service" class="com.example.service.UserServiceImpl">
        <constructor-arg index="0" ref="userDao" />
        <constructor-arg index="1" value="defaultRole" />
    </bean>
</beans>

Java 類別

public class UserDaoImpl implements UserDao {
    // 無參構造器 (隱式或顯式)
    public UserDaoImpl() {}
}

public class UserServiceImpl implements UserService {
    private final UserDao userDao;
    private final String defaultRole;
    
    // 帶參構造器
    public UserServiceImpl(UserDao userDao, String defaultRole) {
        this.userDao = userDao;
        this.defaultRole = defaultRole;
    }
}

方式二:靜態工廠方法實例化

原理:容器調用**靜態方法**獲取實例,適用於**單例模式、連接池、複雜初始化邏輯**。

XML 配置

<bean id="sqlSessionFactory" 
      class="org.mybatis.spring.SqlSessionFactoryBean" 
      factory-method="getObject" /> <!-- FactoryBean 介面方法 -->

<!-- 自定義靜態工廠 -->
<bean id="singletonService" 
      class="com.example.factory.ServiceFactory" 
      factory-method="getInstance" />

工廠類別

public class ServiceFactory {
    private static volatile ServiceFactory INSTANCE;
    
    private ServiceFactory() {}
    
    public static ServiceFactory getInstance() { // 必須 static
        if (INSTANCE == null) {
            synchronized (ServiceFactory.class) {
                if (INSTANCE == null) INSTANCE = new ServiceFactory();
            }
        }
        return INSTANCE;
    }
}

方式三:實例工廠方法實例化

原理:先建立**工廠 Bean 實例**,再調用其**非靜態方法**產生目標 Bean。適用於**工廠本身需要依賴注入**、**多種產品系列**。

XML 配置

<!-- 1. 定義工廠 Bean -->
<bean id="carFactory" class="com.example.factory.CarFactory">
    <property name="paintShop" ref="paintShop" /> <!-- 工廠本身注入依賴 -->
</bean>

<!-- 2. 透過工廠方法建立產品 -->
<bean id="sedan" factory-bean="carFactory" factory-method="createSedan" />
<bean id="suv" factory-bean="carFactory" factory-method="createSuv" />
<bean id="truck" factory-bean="carFactory" factory-method="createTruck" />

工廠類別

public class CarFactory {
    private PaintShop paintShop; // 注入依賴
    
    public void setPaintShop(PaintShop paintShop) {
        this.paintShop = paintShop;
    }
    
    // 非靜態方法
    public Car createSedan() {
        Car car = new Sedan();
        paintShop.paint(car, Color.BLACK);
        return car;
    }
    
    public Car createSuv() { /* ... */ }
    public Car createTruck() { /* ... */ }
}

三種方式對比總結

維度構造器靜態工廠實例工廠
配置屬性class + constructor-argclass + factory-methodfactory-bean + factory-method
調用方式new Constructor()StaticFactory.method()factoryInstance.method()
工廠本身是否為 Bean否否**是** (factory-bean)
工廠可注入依賴否否**是**
適用場景90% 一般情況單例、舊 API、複雜建構邏輯抽象工廠、工廠需狀態/依賴
測試友好度高 (構造器注入)中中

進階:FactoryBean 介面 (Spring 內建擴展)

實作 org.springframework.beans.factory.FactoryBean<T>,容器調用 getObject() 獲取真正 Bean:

<bean id="dataSource" class="com.example.factory.CustomDataSourceFactoryBean">
    <property name="url" value="jdbc:mysql://..." />
</bean>

public class CustomDataSourceFactoryBean implements FactoryBean<DataSource> {
    private String url;
    
    @Override
    public DataSource getObject() throws Exception {
        HikariDataSource ds = new HikariDataSource();
        ds.setJdbcUrl(url);
        return ds;
    }
    
    @Override
    public Class<?> getObjectType() { return DataSource.class; }
    
    @Override
    public boolean isSingleton() { return true; }
    
    public void setUrl(String url) { this.url = url; }
}

現代 Spring 最佳實踐 (Java Config / Spring Boot)

@Configuration
public class AppConfig {
    
    // 1. 構造器注入 (推薦)
    @Bean
    public UserService userService(UserDao userDao) {
        return new UserServiceImpl(userDao, "USER");
    }
    
    // 2. 靜態工廠
    @Bean
    public SqlSessionFactory sqlSessionFactory() throws Exception {
        return new SqlSessionFactoryBean().getObject();
    }
    
    // 3. 實例工廠
    @Bean
    public CarFactory carFactory(PaintShop paintShop) {
        return new CarFactory(paintShop);
    }
    
    @Bean
    public Car sedan(CarFactory carFactory) {
        return carFactory.createSedan();
    }
}

總結

  1. 構造器實例化:首選、最自然、支援不可變對象、測試友好
  2. 靜態工廠:封裝複雜建構邏輯、單例、舊版 API 適配
  3. 實例工廠:工廠本身有狀態/依賴、抽象工廠模式、多產品族
  4. XML 配置時代已過,**Java Config (@Configuration + @Bean) 類型安全、重構友好、IDE 支援完整**,新專案請直接使用
  5. 理解底層原理有助於排查循環依賴、初始化順序、代理生成等疑難雜症
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved