五分鐘,手擼一個 Spring 容器!

大家好,我是老三,Spring 是我們最常用的開源框架,經過多年發展,Spring 已經發展成枝繁葉茂的大樹,讓我們難以窺其全貌。

這節,我們迴歸 Spring 的本質,五分鐘手擼一個 Spring 容器,揭開 Spring 神祕的面紗!

從什麼是 IOC 開始?

Spring——春天,Java 編程世界的春天是由一位音樂家——Rod Johnson 帶來的。

Rod Johnson 先後編寫了兩本鉅著《Expert One-on-One J2EE Design and Development》、《Expert One-on-One J2EE Development without EJB》,拉起了挑戰正統 Java EE 框架 EJB 的大旗。

Rod Johnson 兩大著作 - 來自百度百科

Rod Johnson 不僅是一名旗手,更是開發了 Spring 這一輕量級框架,像一名勇敢的龍騎兵一樣,對 EJB 發動了衝鋒,並最終戰勝了 EJB,讓 Spring 成爲 Java EE 事實上的標準。

Spring Logo

Spring 的兩大內核分別是 IOC 和 AOP,其中最最核心的是 IOC。

所謂的 IOC(控制反轉):就是由容器來負責控制對象的生命週期和對象間的關係。以前是我們想要什麼,就自己創建什麼,現在是我們需要什麼,容器就給我們送來什麼。

引入 IOC 之前和引入 IOC 之後

也就是說,控制對象生命週期的不再是引用它的對象,而是容器。對具體對象,以前是它控制其它對象,現在所有對象都被容器控制,所以這就叫控制反轉

控制反轉示意圖

也許你還聽到另外一個概念 DI(依賴注入),它指的是容器在實例化對象的時候把它依賴的類注入給它,我們也可以認爲,DI 是 IOC 的補充和實現。

工廠和 Spring 容器

Spring 是一個成熟的框架,爲了滿足擴展性、實現各種功能,所以它的實現如同枝節交錯的大樹一樣,現在讓我們把視線從 Spring 本身移開,來看看一個萌芽版的 Spring 容器怎麼實現。

Spring 的 IOC 本質就是一個大工廠,我們想想一個工廠是怎麼運行的呢?

工廠運行

那對應我們的萌芽版的 Spring 容器是什麼樣的呢?

mini 版本 Spring IOC

訂單:Bean 定義

Bean 可以通過一個配置文件定義,我們會把它解析成一個類型。

Bean 定義

獲取訂單:資源加載

接下訂單之後,就要由銷售向生產部門交接,讓生產部門知道商品的規格、數量之類。

資源加載器,就是來完成這個工作的,由它來完成配置文件中配置的加載。

public class ResourceLoader {

    public static Map<String, BeanDefinition> getResource() {
        Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>(16);
        Properties properties = new Properties();
        try {
            InputStream inputStream = ResourceLoader.class.getResourceAsStream("/beans.properties");
            properties.load(inputStream);
            Iterator<String> it = properties.stringPropertyNames().iterator();
            while (it.hasNext()) {
                String key = it.next();
                String className = properties.getProperty(key);
                BeanDefinition beanDefinition = new BeanDefinition();
                beanDefinition.setBeanName(key);
                Class clazz = Class.forName(className);
                beanDefinition.setBeanClass(clazz);
                beanDefinitionMap.put(key, beanDefinition);
            }
            inputStream.close();
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
        return beanDefinitionMap;
    }

}

訂單分配:Bean 註冊

對象註冊器,這裏用於單例 bean 的緩存,我們大幅簡化,默認所有 bean 都是單例的。可以看到所謂單例註冊,也很簡單,不過是往 HashMap 裏存對象。

public class BeanRegister {

    //單例Bean緩存
    private Map<String, Object> singletonMap = new HashMap<>(32);

    /**
     * 獲取單例Bean
     *
     * @param beanName bean名稱
     * @return
     */
    public Object getSingletonBean(String beanName) {
        return singletonMap.get(beanName);
    }

    /**
     * 註冊單例bean
     *
     * @param beanName
     * @param bean
     */
    public void registerSingletonBean(String beanName, Object bean) {
        if (singletonMap.containsKey(beanName)) {
            return;
        }
        singletonMap.put(beanName, bean);
    }

}

生產車間:對象工廠

好了,到了我們最關鍵的生產部門了,在工廠裏,生產產品的是車間,在 IOC 容器裏,生產對象的是 BeanFactory。

BeanFactory

生產銷售:測試

至此,我們一個萌芽版的 Spring 容器就完成了。

考慮一下,它有哪些不足呢?是否還可以抽象、擴展、解耦……

細細想想這些東西,你是不是對真正的 Spring IOC 容器爲何如此複雜,有所理解了呢?

參考:

三分惡 CSDN 博客專家、優質創作者,華爲云云享專家;肝過外包、混過國企,目前在一家跨境電商搬磚;寫過詩,打過拳,佛系小碼農。認真講技術,隨性侃人生,關注我,我們一起走的更遠。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/25vybHVeXD-IdzejKYpCVg