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

手把手教你實作簡易版 Spring IoC 容器

     編輯:Java 相關知識

從零開始理解 Spring 核心機制

Spring 框架的核心在於控制反轉(IoC)與依賴注入(DI)。本文透過手寫一個簡易版 IoC 容器,深入剖析 Spring 如何管理 Bean 生命週期、解析 XML 設定、實現依賴注入。

專案架構設計

採用標準分層架構:

  • model:實體類別
  • dao:資料存取介面
  • dao.impl:DAO 實作類別
  • service:業務邏輯層
  • spring:自訂 IoC 容器核心

核心元件實作

1. 實體與 DAO 介面

// model/User.java
public class User {
    private String username;
    private String password;
    // getter/setter 略
}

// dao/UserDAO.java
public interface UserDAO {
    void save(User user);
}

// dao/impl/UserDAOImpl.java
public class UserDAOImpl implements UserDAO {
    @Override
    public void save(User user) {
        System.out.println("儲存用戶: " + user.getUsername());
    }
}

2. 服務層與依賴注入

服務類別透過 setter 注入 DAO 依賴,體現「面向介面程式設計」與「依賴倒置原則」:

// service/UserService.java
public class UserService {
    private UserDAO userDAO;

    public void setUserDAO(UserDAO userDAO) {
        this.userDAO = userDAO;
    }

    public void add(User user) {
        userDAO.save(user);
    }
}

3. XML 設定檔

定義 Bean 及其依賴關係:

<beans>
    <bean id="userDAO" class="com.example.dao.impl.UserDAOImpl" />
    <bean id="userService" class="com.example.service.UserService">
        <property name="userDAO" ref="userDAO"/>
    </bean>
</beans>

4. 自訂 BeanFactory 介面

// spring/BeanFactory.java
public interface BeanFactory {
    Object getBean(String name);
}

5. 核心容器實作:解析 XML、建立 Bean、注入依賴

// spring/ClassPathXmlApplicationContext.java
public class ClassPathXmlApplicationContext implements BeanFactory {
    private Map<String, Object> beans = new HashMap<>();

    public ClassPathXmlApplicationContext() throws Exception {
        // 1. 解析 XML
        SAXBuilder builder = new SAXBuilder();
        Document doc = builder.build(getClass().getClassLoader()
            .getResourceAsStream("beans.xml"));
        Element root = doc.getRootElement();
        List<Element> beanElements = root.getChildren("bean");

        // 2. 建立所有 Bean 實例
        for (Element elem : beanElements) {
            String id = elem.getAttributeValue("id");
            String className = elem.getAttributeValue("class");
            Object bean = Class.forName(className).newInstance();
            beans.put(id, bean);
        }

        // 3. 處理依賴注入
        for (Element elem : beanElements) {
            String id = elem.getAttributeValue("id");
            Object bean = beans.get(id);
            List<Element> props = elem.getChildren("property");
            for (Element prop : props) {
                String name = prop.getAttributeValue("name"); // 屬性名
                String ref = prop.getAttributeValue("ref");   // 依賴的 bean id
                Object depBean = beans.get(ref);
                
                // 反射呼叫 setter
                String setterName = "set" + name.substring(0,1).toUpperCase() + name.substring(1);
                Method setter = bean.getClass().getMethod(setterName, depBean.getClass().getInterfaces()[0]);
                setter.invoke(bean, depBean);
            }
        }
    }

    @Override
    public Object getBean(String name) {
        return beans.get(name);
    }
}

測試驗證

// service/UserServiceTest.java
public class UserServiceTest {
    @Test
    public void testAdd() throws Exception {
        BeanFactory factory = new ClassPathXmlApplicationContext();
        UserService service = (UserService) factory.getBean("userService");
        User user = new User();
        user.setUsername("testUser");
        service.add(user); // 輸出: 儲存用戶: testUser
    }
}

核心流程總結

  1. 掃描與實例化:讀取 XML,透過反射建立所有 Bean 實例
  2. 依賴解析:分析 <property> 元素,識別 Bean 間依賴
  3. 反射注入:動態呼叫 setter 方法,將依賴物件注入目標 Bean
  4. 容器管理:Bean 存放於 Map 中,透過 getBean() 提供存取

現代 Spring 的演進

實際 Spring 框架在此基礎上擴展了:

  • 支援註解配置(@Component, @Autowired)
  • Bean 生命週期回調
  • AOP 切面程式設計
  • 事務管理
  • 條件裝配與 Profile 環境隔離
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved