1. 程式人生 > >跟我猜Spring-Boot:bean的建立

跟我猜Spring-Boot:bean的建立

## 廢話在前 最近幾年的技術路子很雜,先是node,然後是php,後來是openresty,再後來轉到了java,而接觸的框架(Framework),也越發的複雜,從最開始的express/koa,到lumen ,再到spring全家桶,各種切換,也確實一度頭疼; 一般而言,學習一種技術下的某種框架當然是去讀原始碼,但開源專案動轍幾萬十幾萬行,尤其我又是個懶人,實在是沒辦法分析瞭解。於是,我選擇了另一種方式,即在使用框架過程中去“猜想“,即去思考他應該去怎麼實驗的; 其實,不停的猜想,然後寫小demo去實現,再到框架原始碼中針對性的找到機制去閱讀,也不失為一種樂趣。 出於這種思維,我在工作中不停的接觸過往同事的原始碼,再從原始碼中學習到spring各種特性的用法,再去猜想,實現,檢視程式碼去驗證,也確實為工作添了些許樂趣。出於這種目的,想把自己這些的猜想做一些整理,與大家分享。z 本系列的文章預謀好久,然而一直不知道該如何開始,不如寫一篇算一篇。在這些文章中,我將先去寫一個spring的應用特性,然後靠“猜想“去將背後的特性實現出來。 那麼本篇,從最基本的入口程式開始吧。 從這個入口程式,我們將看到一個spring bean建立的簡單機制。 ## 目標 在本篇文章中,我們要實現一個spring的入口程式,即: **App.java** ```java package com.github.yfge.miniapp; import com.github.yfge.miniboot.autoconfigure.BootApplication; import com.github.yfge.miniboot.autoconfigure.Application; @BootApplication(Name = "Hello") public class App { public static void main(String[] args) { Application.run(com.github.yfge.miniapp.App.class); } } ``` 同時,定義一個簡單的`controller`和`service`: **SimpleController.java** ```java package com.github.yfge.miniapp; import com.github.yfge.miniboot.autoconfigure.Autowired; import com.github.yfge.miniboot.autoconfigure.Service; @Service public class SimpleController { @Autowired private SimpleService simpleService; public SimpleController(){ System.out.println("the controller is created!"); } } ``` **SimpleService.java** ```java package com.github.yfge.miniapp; import com.github.yfge.miniboot.autoconfigure.Service; @Service public class SimpleService { public SimpleService(){ System.out.println("the service is created!"); } } ``` 即我們要通過這個入口程式的執行,看到`service`和`controller`被**自動**的建立。 通過這三個檔案的import也看到了,**我們沒有引用spring-boot**,而是自己寫了一些簡單的類引用進來,來**模擬**spring-boot 在這種情況下,我們整個專案很自然分成兩個module: * mini-app,用來模擬我們的應用 * mini-boot,用來模擬spring-boot框架 ## bean建立的需求分析 > sorry 我實在想不來有什麼比需求分析更適合這節標題 :) 如果我們要達到上述的目標,那我們的小框架應該實現如下的功能: 1. 定義相應的annotation 2. 自動掃描相應的類 3. 如果類被標明是service,那麼它應該被自動建立 那麼下面,就按這三步來實現我們的目標。 ## step 1 定義相應的anotation 從我們的目標程式,可以看到,我們需要有`BootApplication`和`Service`兩個annotation 既然沒有引用spring-boot,那麼只能自己動手了 這裡為了與spring-boot對齊 (因為我們是模擬麼),直接照搬名稱空間和類名。 **BootApplication.java** ```java package com.github.yfge.miniboot.autoconfigure; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface BootApplication { String Value() default ""; String Name() default ""; } ``` **Service.java** ```java package com.github.yfge.miniboot.autoconfigure; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface Service { String value() default ""; } ``` 這裡要注意一點,**@Retention(RetentionPolicy.RUNTIME)** 這個註解非常重要,因為只有定義為執行時,我們在程式執行的時候才有可能被掃描到。 ## Step3 實現包的類掃描 關於包的類掃描,網上可以到到N種實現,這裡不表述了,直接copy一個現成的 (是的,我們都是程式碼的搬運工