手寫web服務器:實現(xiàn)ComponentScan注解,根據指定包名進行組件掃描

前言
手寫web服務器,到今天已經實現(xiàn)了controller、RequestMapping、RequestParameter、Service還有簡易的Ioc,從構成要素上將我們的小項目已經算是一個比較完整的服務器了,但也有很多需要優(yōu)化的地方,今天我們就來實現(xiàn)ComponentScan注解,優(yōu)化一下包掃描,實現(xiàn)可以根據我們指定的包名進行組件掃描。
這個注解,功能上我們參考了spring,因為是純手寫,所以我們并沒有去看spring的源碼,最近確實也沒時間看。
整起來
今天核心的工作就兩個,首先是定義一個新的注解,然后我們根據這個注解去掃描指定的包。如果注解不存在,我們就從服務器入口,即SyskeBootServerApplication類所在包開始掃描。
定義ComponentScan注解
現(xiàn)在定義注解以及是輕車熟路了 ,so easy!這里的value()方法定義的是數組,用于接受需要掃描的包名,也就是說我們也是支持多包名的。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ComponentScan {
String[] value() ;
}
然后把ComponentScan注解加在我們服務的入口上:

為什么要加在服務器入口上呢?這是我人為規(guī)定的,現(xiàn)在還沒有實現(xiàn)Configuration注解,加在服務器主入口是最好的選擇。
優(yōu)化包掃描器
根據注解內容優(yōu)化包掃描器:
/**
* 掃描指定的包路徑,如果無該路徑,則默認掃描服務器核心入口所在路徑
* @param aClass
* @throws IOException
* @throws ClassNotFoundException
*/
private static void componentScanInit(Class aClass) throws IOException, ClassNotFoundException {
logger.info("componentScanInit start init……");
logger.info("componentScanInit aClass: {}", aClass);
Annotation annotation = aClass.getAnnotation(ComponentScan.class);
if (Objects.isNull(annotation)) {
Package aPackage = aClass.getPackage();
scanPackage(aPackage.toString(), classSet);
} else {
String[] value = ((ComponentScan)annotation).value();
for (String s : value) {
scanPackage(s, classSet);
}
}
logger.info("componentScanInit end, classSet = {}", classSet);
}
在服務器啟動時,需要先執(zhí)行componentScanInit方法,這個方法需要傳入一個Class,也就是我們項目的主入口的類。
方法內部會先判斷這個類是否有ComponentScan注解,如果有則根據注解value()的值進行掃描,否則拿到傳入類的包路徑,然后開始掃描。
測試
運行啟動下,我們發(fā)現(xiàn)控制臺已經打印出了掃描到的類:

總結
今天的內容依然很簡單,就只是實現(xiàn)了一個注解,然后根據這個注解優(yōu)化了我們包掃描的業(yè)務代碼,沒有什么復雜的知識點,后面我們還需要對很多功能進行優(yōu)化,包括以下幾點:
post請求處理與響應GetMapping、PostMapping的實現(xiàn),這個兩個注解實現(xiàn)起來很簡單了,和RequestMapping基本上一致配置注解的實現(xiàn): value、ConfigurationPropertiesget請求頁面模板實現(xiàn)集中異常處理
目前大概能想到這幾點,其他的等后面再說。明天應該會先解決post請求這塊,思路已經有了。好了,今天就先到這里吧!
下面是項目的開源倉庫,有興趣的小伙伴可以去看看,如果有想法的小伙伴,我真心推薦你自己動個手,自己寫一下,真的感覺不錯:
https://github.com/Syske/syske-boot

