1. 小試牛刀,實現(xiàn)一個簡單的Bean容器!

        共 6339字,需瀏覽 13分鐘

         ·

        2021-07-05 07:17

        ?

        沉淀、分享、成長,讓自己和他人都能有所收獲!??

        ?

        目錄

        • 一、前言

        • 二、目標

        • 三、設(shè)計

        • 四、實現(xiàn)

          • 1. 工程結(jié)構(gòu)

          • 2. Bean 定義

          • 3. Bean 工廠

        • 五、測試

          • 1. 事先準備

          • 2. 測試用例

          • 3. 測試結(jié)果

        • 六、總結(jié)

        • 七、系列推薦

        一、前言

        上學時,老師總說:不會你就問,但多數(shù)時候都不知道要問什么!

        你總會在文章前言里,發(fā)現(xiàn)一些關(guān)于成長、學習、感悟以及對當篇內(nèi)容的一個介紹,其實之所以寫這樣的鋪墊性內(nèi)容,主要是為了讓大家對接下來的內(nèi)容學習有一個較輕松的開場和過度。

        就像我們上學時如果某一科的內(nèi)容不會時,老師經(jīng)常會說,你有不會的就要問。但對于學生本身來講,可能已經(jīng)不會的太多了,或者壓根不知道自己不會什么,只有等看到老師出完的試卷才發(fā)現(xiàn)自己什么都不會。但要是讓問,又不知道從哪問,問出蘿卜帶出泥,到處都是知識漏洞。

        所以我希望用一些前置內(nèi)容的鋪墊,讓大家可以在一個稍有共識的場景下進行學習,或多或少能為你鋪墊出一個稍許平緩的接受期。有可能某些時候也會打打雞血、刺激刺激學習、總歸把知識學到手就是好的!

        二、目標

        Spring Bean 容器是什么?

        Spring 包含并管理應用對象的配置和生命周期,在這個意義上它是一種用于承載對象的容器,你可以配置你的每個 Bean 對象是如何被創(chuàng)建的,這些 Bean 可以創(chuàng)建一個單獨的實例或者每次需要時都生成一個新的實例,以及它們是如何相互關(guān)聯(lián)構(gòu)建和使用的。

        如果一個 Bean 對象交給 Spring 容器管理,那么這個 Bean 對象就應該以類似零件的方式被拆解后存放到 Bean 的定義中,這樣相當于一種把對象解耦的操作,可以由 Spring 更加容易的管理,就像處理循環(huán)依賴等操作。

        當一個 Bean 對象被定義存放以后,再由 Spring 統(tǒng)一進行裝配,這個過程包括 Bean 的初始化、屬性填充等,最終我們就可以完整的使用一個 Bean 實例化后的對象了。

        而我們本章節(jié)的案例目標就是定義一個簡單的 Spring 容器,用于定義、存放和獲取 Bean 對象。

        三、設(shè)計

        凡是可以存放數(shù)據(jù)的具體數(shù)據(jù)結(jié)構(gòu)實現(xiàn),都可以稱之為容器。例如:ArrayList、LinkedList、HashSet等,但在 Spring Bean 容器的場景下,我們需要一種可以用于存放和名稱索引式的數(shù)據(jù)結(jié)構(gòu),所以選擇 HashMap 是最合適不過的。

        這里簡單介紹一下 HashMap,HashMap 是一種基于擾動函數(shù)、負載因子、紅黑樹轉(zhuǎn)換等技術(shù)內(nèi)容,形成的拉鏈尋址的數(shù)據(jù)結(jié)構(gòu),它能讓數(shù)據(jù)更加散列的分布在哈希桶以及碰撞時形成的鏈表和紅黑樹上。它的數(shù)據(jù)結(jié)構(gòu)會盡可能最大限度的讓整個數(shù)據(jù)讀取的復雜度在 O(1) ~ O(Logn) ~O(n)之間,當然在極端情況下也會有 O(n) 鏈表查找數(shù)據(jù)較多的情況。不過我們經(jīng)過10萬數(shù)據(jù)的擾動函數(shù)再尋址驗證測試,數(shù)據(jù)會均勻的散列在各個哈希桶索引上,所以 HashMap 非常適合用在 Spring Bean 的容器實現(xiàn)上。

        另外一個簡單的 Spring Bean 容器實現(xiàn),還需 Bean 的定義、注冊、獲取三個基本步驟,簡化設(shè)計如下;

        • 定義:BeanDefinition,可能這是你在查閱 Spring 源碼時經(jīng)常看到的一個類,例如它會包括 singleton、prototype、BeanClassName 等。但目前我們初步實現(xiàn)會更加簡單的處理,只定義一個 Object 類型用于存放對象。
        • 注冊:這個過程就相當于我們把數(shù)據(jù)存放到 HashMap 中,只不過現(xiàn)在 HashMap 存放的是定義了的 Bean 的對象信息。
        • 獲?。鹤詈缶褪谦@取對象,Bean 的名字就是key,Spring 容器初始化好 Bean 以后,就可以直接獲取了。

        接下來我們就按照這個設(shè)計,做一個簡單的 Spring Bean 容器代碼實現(xiàn)。編碼的過程往往并不會有多復雜,但知曉設(shè)計過程卻更加重要!

        四、實現(xiàn)

        1. 工程結(jié)構(gòu)

        small-spring-step-01
        └── src
            ├── main
            │   └── java
            │       └── cn.bugstack.springframework
            │           ├── BeanDefinition.java
            │           └── BeanFactory.java
            └── test
                └── java
                    └── cn.bugstack.springframework.test  
                        ├── bean
                        │   └── UserService.java                
                        └── ApiTest.java

        工程源碼:https://github.com/small-spring/small-spring-step-01

        Spring Bean 容器類關(guān)系,如圖 2-2

        圖 2-2

        Spring Bean 容器的整個實現(xiàn)內(nèi)容非常簡單,也僅僅是包括了一個簡單的 BeanFactory 和 BeanDefinition,這里的類名稱是與 Spring 源碼中一致,只不過現(xiàn)在的類實現(xiàn)會相對來說更簡化一些,在后續(xù)的實現(xiàn)過程中再不斷的添加內(nèi)容。

        1. BeanDefinition,用于定義 Bean 實例化信息,現(xiàn)在的實現(xiàn)是以一個 Object 存放對象
        2. BeanFactory,代表了 Bean 對象的工廠,可以存放 Bean 定義到 Map 中以及獲取。

        2. Bean 定義

        cn.bugstack.springframework.BeanDefinition

        public class BeanDefinition {

            private Object bean;

            public BeanDefinition(Object bean) {
                this.bean = bean;
            }

            public Object getBean() {
                return bean;
            }

        }
        • 目前的 Bean 定義中,只有一個 Object 用于存放 Bean 對象。如果感興趣可以參考 Spring 源碼中這個類的信息,名稱都是一樣的。
        • 不過在后面陸續(xù)的實現(xiàn)中會逐步完善 BeanDefinition 相關(guān)屬性的填充,例如:SCOPE_SINGLETON、SCOPE_PROTOTYPE、ROLE_APPLICATION、ROLE_SUPPORT、ROLE_INFRASTRUCTURE 以及 Bean Class 信息。

        3. Bean 工廠

        cn.bugstack.springframework.BeanFactory

        public class BeanFactory {

            private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();

            public Object getBean(String name) {
                return beanDefinitionMap.get(name).getBean();
            }

            public void registerBeanDefinition(String name, BeanDefinition beanDefinition) {
                beanDefinitionMap.put(name, beanDefinition);
            }

        }
        • 在 Bean 工廠的實現(xiàn)中,包括了 Bean 的注冊,這里注冊的是 Bean 的定義信息。同時在這個類中還包括了獲取 Bean 的操作。
        • 目前的 BeanFactory 仍然是非常簡化的實現(xiàn),但這種簡化的實現(xiàn)內(nèi)容也是整個 Spring 容器中關(guān)于 Bean 使用的最終體現(xiàn)結(jié)果,只不過實現(xiàn)過程只展示出基本的核心原理。在后續(xù)的補充實現(xiàn)中,這個會不斷變得龐大。

        五、測試

        1. 事先準備

        cn.bugstack.springframework.test.bean.UserService

        public class UserService {

            public void queryUserInfo(){
                System.out.println("查詢用戶信息");
            }

        }
        • 這里簡單定義了一個 UserService  對象,方便我們后續(xù)對 Spring 容器測試。

        2. 測試用例

        cn.bugstack.springframework.test.ApiTest

        @Test
        public void test_BeanFactory(){
            // 1.初始化 BeanFactory
            BeanFactory beanFactory = new BeanFactory();
            
            // 2.注冊 bean
            BeanDefinition beanDefinition = new BeanDefinition(new UserService());
            beanFactory.registerBeanDefinition("userService", beanDefinition);
            
            // 3.獲取 bean
            UserService userService = (UserService) beanFactory.getBean("userService");
            userService.queryUserInfo();
        }
        • 在單測中主要包括初始化 Bean 工廠、注冊 Bean、獲取 Bean,三個步驟,使用效果上貼近與 Spring,但顯得會更簡化。
        • 在 Bean 的注冊中,這里是直接把 UserService 實例化后作為入?yún)鬟f給 BeanDefinition 的,在后續(xù)的陸續(xù)實現(xiàn)中,我們會把這部分內(nèi)容放入 Bean 工廠中實現(xiàn)。

        3. 測試結(jié)果

        查詢用戶信息

        Process finished with exit code 0
        • 通過測試結(jié)果可以看到,目前的 Spring Bean 容器案例,已經(jīng)稍有雛形。

        六、總結(jié)

        • 整篇關(guān)于 Spring Bean 容器的一個雛形就已經(jīng)實現(xiàn)完成了,相對來說這部分代碼并不會難住任何人,只要你稍加嘗試就可以接受這部分內(nèi)容的實現(xiàn)。
        • 但對于一個知識的學習來說,寫代碼只是最后的步驟,往往整個思路、設(shè)計、方案,才更重要,只要你知道了因為什么、所以什么,才能讓你有一個真正的理解。
        • 下一章節(jié)會在此工程基礎(chǔ)上擴容實現(xiàn),要比現(xiàn)在的類多一些。不過每一篇的實現(xiàn)上,我都會以一個需求視角進行目標分析和方案設(shè)計,讓大家在學習編碼之外更能注重更多技術(shù)價值的學習。
        瀏覽 40
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
          
          

            1. 亚洲 图片 小说 欧美 另类 | 国产美女操 | 91禁看片| 在野外被二个男人躁一夜 | 欧美六十路 |