<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          手寫一個(gè)HTTP框架:兩個(gè)類實(shí)現(xiàn)基本的IoC功能

          共 8302字,需瀏覽 17分鐘

           ·

          2020-10-14 07:05

          jsoncat:https://github.com/Snailclimb/jsoncat?(仿 Spring Boot 但不同于 Spring Boot 的一個(gè)輕量級(jí)的 HTTP 框架)

          國(guó)慶節(jié)的時(shí)候,我就已經(jīng)把 jsoncat 的?IoC 功能給寫了,具體可以看這篇文章手寫“SpringBoot”近況:IoC模塊已經(jīng)完成 。

          今天這篇文章就來(lái)簡(jiǎn)單分享一下自己寫 IoC 的思路與具體的代碼實(shí)現(xiàn)。

          IoC (Inverse of Control:控制反轉(zhuǎn))AOP(Aspect-Oriented Programming:面向切面編程) 可以說(shuō)是 Spring 框架提供的最核心的兩個(gè)功能。但凡是了解過(guò) Spring 的小伙伴,那肯定對(duì)這個(gè)兩個(gè)概念非常非常了解。不了解的小伙伴,可以查看《面試被問(wèn)了幾百遍的 IoC 和 AOP ,還在傻傻搞不清楚?》這篇通俗易懂的文章。

          考慮到這篇文章要手寫 Spring 框架的 IoC 功能,所以,我這里還是簡(jiǎn)單介紹一下 IoC 。如果你不太清楚 IoC 這個(gè)概念,一定要搞懂之后再看后面具體的代碼實(shí)現(xiàn)環(huán)節(jié)。

          IoC 介紹

          IoC(Inverse of Control:控制反轉(zhuǎn))是一種設(shè)計(jì)思想,也就是 將原本在程序中手動(dòng)創(chuàng)建對(duì)象的控制權(quán)交由Spring框架來(lái)管理。 IoC 在其他語(yǔ)言中也有應(yīng)用,并非 Spring 特有。

          IoC 容器

          IoC 容器是用來(lái)實(shí)現(xiàn) IoC 的載體,被管理的對(duì)象就被存放在IoC容器中。IoC 容器在 Spring 中實(shí)際上就是個(gè)Map(key,value),Map 中存放了各種被管理的對(duì)象。

          IoC 解決了什么問(wèn)題

          將對(duì)象之間的相互依賴關(guān)系交給 IoC 容器來(lái)管理,并由 IoC 容器完成對(duì)象的注入。這樣可以很大程度上簡(jiǎn)化應(yīng)用的開發(fā),把應(yīng)用從復(fù)雜的依賴關(guān)系中解放出來(lái)。IoC 容器就像是一個(gè)工廠一樣,當(dāng)我們需要?jiǎng)?chuàng)建一個(gè)對(duì)象的時(shí)候,只需要配置好配置文件/注解即可,完全不用考慮對(duì)象是如何被創(chuàng)建出來(lái)的。?

          IoC 和 DI 別再傻傻分不清楚

          IoC(Inverse of Control:控制反轉(zhuǎn))是一種設(shè)計(jì)思想 或者說(shuō)是某種模式。這個(gè)設(shè)計(jì)思想就是 將原本在程序中手動(dòng)創(chuàng)建對(duì)象的控制權(quán),交由 Spring 框架來(lái)管理。 IoC 在其他語(yǔ)言中也有應(yīng)用,并非 Spring 特有。IoC 容器是 Spring 用來(lái)實(shí)現(xiàn) IoC 的載體, IoC 容器實(shí)際上就是個(gè) Map(key,value),Map 中存放的是各種被管理的對(duì)象。

          IoC 最常見以及最合理的實(shí)現(xiàn)方式叫做依賴注入(Dependency Injection,簡(jiǎn)稱 DI)。

          并且,老馬(Martin Fowler)在一篇文章中提到將 IoC 改名為 DI,原文如下,原文地址:https://martinfowler.com/articles/injection.html 。

          IoC實(shí)現(xiàn)思路

          ?注意 :以下思路未涉及解決循環(huán)依賴的問(wèn)題!

          開始代碼實(shí)現(xiàn)之前,我們先簡(jiǎn)單聊聊實(shí)現(xiàn) IoC 的思路,搞清楚了思路之后,實(shí)現(xiàn)起來(lái)就非常簡(jiǎn)單了。

          1. 掃描指定包下的特定注解比如@Component標(biāo)記的類,并將這些類保存起來(lái)。
          2. 遍歷所有被特定注解比如@Component標(biāo)記的類,然后將這些類通過(guò)反射實(shí)例化并通過(guò)一個(gè) Map 保存起來(lái),Map 的 key 為類名,value為類對(duì)象。
          3. 再一次遍歷所有被特定注解比如@Component標(biāo)記的類,并獲取類中所有的字段,如果類被 @Autowired 注解標(biāo)記的話,就進(jìn)行第 4 步。
          4. 通過(guò)字段名 key,從bean容器中獲取對(duì)應(yīng)的對(duì)象 value。
          5. 判斷獲取到的對(duì)象是否為接口。如果是接口的話,需要獲取接口對(duì)應(yīng)的實(shí)現(xiàn)類,然后再將指定的實(shí)現(xiàn)類的實(shí)例化對(duì)象通過(guò)反射賦值給指定對(duì)象。如果不是接口的話,就直接將獲取到的對(duì)象通過(guò)反射賦值給指定對(duì)象。

          IoC 實(shí)現(xiàn)核心代碼

          核心注解

          @Autowired :注解對(duì)象

          @Target(ElementType.FIELD)
          @Retention(RetentionPolicy.RUNTIME)
          @Documented
          public?@interface?Autowired?{

          }

          @Component :聲明對(duì)象被IoC容器管理


          @Target(ElementType.TYPE)
          @Retention(RetentionPolicy.RUNTIME)
          @Documented
          public?@interface?Component?{
          ????String?name()?default?"";
          }

          @Qualifier: 指定注入的bean(當(dāng)接口有多個(gè)實(shí)現(xiàn)類的時(shí)候需要使用)

          @Target({ElementType.FIELD,?ElementType.METHOD,?ElementType.PARAMETER,?ElementType.TYPE,?ElementType.ANNOTATION_TYPE})
          @Retention(RetentionPolicy.RUNTIME)
          @Inherited
          @Documented
          public?@interface?Qualifier?{
          ????String?value()?default?"";
          }

          工具類

          簡(jiǎn)單封裝一個(gè)反射工具類。工具類包含3個(gè)后面會(huì)用到的方法:

          1. scanAnnotatedClass() ?:掃描指定包下的被指定注解標(biāo)記的類(使用Reflections這個(gè)反射框架一行代碼即可解決掃描獲取指定注解的類)。
          2. newInstance() : 傳入 Class 即可返回 Class 對(duì)應(yīng)的對(duì)象。
          3. setField() :為對(duì)象的指定字段賦值。
          @Slf4j
          public?class?ReflectionUtil?{
          ????/**
          ?????*?scan?the?classes?marked?by?the?specified?annotation?in?the?specified?package
          ?????*
          ?????*?@param?packageName?specified?package?name
          ?????*?@param?annotation??specified?annotation
          ?????*?@return?the?classes?marked?by?the?specified?annotation?in?the?specified?package
          ?????*/

          ????public?static?Set>?scanAnnotatedClass(String?packageName,?Class?annotation)?{
          ????????Reflections?reflections?=?new?Reflections(packageName,?new?TypeAnnotationsScanner());
          ????????Set>?annotatedClass?=?reflections.getTypesAnnotatedWith(annotation,?true);
          ????????log.info("The?number?of?class?Annotated?with??@RestController?:[{}]",?annotatedClass.size());
          ????????return?annotatedClass;
          ????}

          ????/**
          ?????*?create?object?instance?through?class
          ?????*
          ?????*?@param?cls?target?class
          ?????*?@return?object?created?by?the?target?class
          ?????*/

          ????public?static?Object?newInstance(Class?cls)?{
          ????????Object?instance?=?null;
          ????????try?{
          ????????????instance?=?cls.newInstance();
          ????????}?catch?(InstantiationException?|?IllegalAccessException?e)?{
          ????????????log.error("new?instance?failed",?e);
          ????????}
          ????????return?instance;
          ????}

          ????/**
          ?????*?set?the?value?of?a?field?in?the?object
          ?????*
          ?????*?@param?obj???target?object
          ?????*?@param?field?target?field
          ?????*?@param?value?the?value?assigned?to?the?field
          ?????*/

          ????public?static?void?setField(Object?obj,?Field?field,?Object?value)?{

          ????????field.setAccessible(true);
          ????????try?{
          ????????????field.set(obj,?value);
          ????????}?catch?(IllegalAccessException?e)?{
          ????????????log.error("set?field?failed",?e);
          ????????????e.printStackTrace();
          ????????}

          ????}
          ??
          }

          根據(jù)實(shí)現(xiàn)思路寫代碼

          ?注意 :以下代碼未涉及解決循環(huán)依賴的問(wèn)題!以下是 IoC 實(shí)現(xiàn)的核心代碼,完整代碼地址:https://github.com/Snailclimb/jsoncat 。

          1.掃描指定包下的特定注解比如@Component標(biāo)記的類,并將這些類保存起來(lái)。

          掃描指定注解@RestController@Component并保存起來(lái):

          public?class?ClassFactory?{
          ????public?static?final?Map,?Set>>?CLASSES?=?new?ConcurrentHashMap<>();
          ????//1.掃描指定包下的特定注解比如`@Component`標(biāo)記的類,并將這些類保存起來(lái)
          ????public?static?void?loadClass(String?packageName)?{
          ????????Set>?restControllerSets?=?ReflectionUtil.scanAnnotatedClass(packageName,?RestController.class);
          ????????Set>?componentSets?=?ReflectionUtil.scanAnnotatedClass(packageName,?Component.class);
          ????????CLASSES.put(RestController.class,?restControllerSets);
          ????????CLASSES.put(Component.class,?componentSets);
          ????}
          }

          2.遍歷所有被特定注解比如@Component標(biāo)記的類,然后將這些類通過(guò)反射實(shí)例化并通過(guò)一個(gè) Map 保存起來(lái),Map 的 key 為類名,value為類對(duì)象。

          public?final?class?BeanFactory?{
          ????public?static?final?Map?BEANS?=?new?ConcurrentHashMap<>(128);

          ????public?static?void?loadBeans()?{

          ????????//?2.遍歷所有被特定注解比如?@Component?標(biāo)記的類,然后將這些類通過(guò)反射實(shí)例化并通過(guò)一個(gè)?Map?保存起來(lái),Map?的?key?為類名,value為類對(duì)象
          ????????ClassFactory.CLASSES.forEach((annotation,?classes)?->?{
          ????????????if?(annotation?==?Component.class)?{
          ????????????????//將bean實(shí)例化,?并放入bean容器中
          ????????????????for?(Class?aClass?:?classes)?{
          ????????????????????Component?component?=?aClass.getAnnotation(Component.class);
          ????????????????????String?beanName?=?"".equals(component.name())???aClass.getName()?:?component.name();
          ????????????????????Object?obj?=?ReflectionUtil.newInstance(aClass);
          ????????????????????BEANS.put(beanName,?obj);
          ????????????????}
          ????????????}

          ????????????if?(annotation?==?RestController.class)?{
          ????????????????for?(Class?aClass?:?classes)?{
          ????????????????????Object?obj?=?ReflectionUtil.newInstance(aClass);
          ????????????????????BEANS.put(aClass.getName(),?obj);
          ????????????????}
          ????????????}
          ????????});
          ????}
          }

          3.再一次遍歷所有被特定注解比如@Component標(biāo)記的類,并獲取類中所有的字段,如果類被 @Autowired 注解標(biāo)記的話,就進(jìn)行第 4 步。

          public?class?DependencyInjection?{

          ????public?static?void?dependencyInjection(String?packageName)?{
          ????????Map?beans?=?BeanFactory.BEANS;
          ????????if?(beans.size()?==?0)?return;
          ????????//3.再一次遍歷所有被特定注解比如?@Component 標(biāo)記的類,并獲取類中所有的字段,如果類被?`@Autowired`?注解標(biāo)記的話,就進(jìn)行第 4 步。
          ????????//?3.1.遍歷bean容器中的所有對(duì)象
          ????????beans.values().forEach(bean?->?{
          ????????????//?3.2.獲取對(duì)象所屬的類聲明的所有字段/屬性
          ????????????Field[]?beanFields?=?bean.getClass().getDeclaredFields();
          ????????????if?(beanFields.length?==?0)?return;
          ????????????//3.3.遍歷對(duì)象所屬的類聲明的所有字段/屬性
          ????????????for?(Field?beanField?:?beanFields)?{
          ??????????????//3.4.判斷字段是否被?@Autowired?注解標(biāo)記
          ????????????????if?(beanField.isAnnotationPresent(Autowired.class))?{
          ????????????????????//4.通過(guò)字段名 key,從bean容器中獲取對(duì)應(yīng)的對(duì)象 value。
          ????????????????????//4.1.字段對(duì)應(yīng)的類型
          ????????????????????Class?beanFieldClass?=?beanField.getType();
          ????????????????????//4.2.字段對(duì)應(yīng)的類名
          ????????????????????String?beanName?=?beanFieldClass.getName();
          ????????????????????if?(beanFieldClass.isAnnotationPresent(Component.class))?{
          ????????????????????????Component?component?=?beanFieldClass.getAnnotation(Component.class);
          ????????????????????????beanName?=?"".equals(component.name())???beanFieldClass.getName()?:?component.name();
          ????????????????????}
          ????????????????????//4.3.從bean容器中獲取對(duì)應(yīng)的對(duì)象
          ????????????????????Object?beanFieldInstance?=?beans.get(beanName);
          ????????????????????//5.判斷獲取到的對(duì)象是否為接口。如果是接口的話,需要獲取接口對(duì)應(yīng)的實(shí)現(xiàn)類,然后再將指定的實(shí)現(xiàn)類的實(shí)例化對(duì)象通過(guò)反射賦值給指定對(duì)象。如果不是接口的話,就直接將獲取到的對(duì)象通過(guò)反射賦值給指定對(duì)象。
          ????????????????????if?(beanFieldClass.isInterface())?{
          ????????????????????????//如果是接口,獲取接口對(duì)應(yīng)的實(shí)現(xiàn)類
          ????????????????????????Set>?subClasses?=?getSubClass(packageName,?beanFieldClass);
          ????????????????????????//沒有實(shí)現(xiàn)類的話就拋出異常
          ????????????????????????if?(subClasses.size()?==?0)?{
          ????????????????????????????throw?new?InterfaceNotHaveImplementedClassException("interface?does?not?have?implemented?class?exception");
          ????????????????????????}
          ????????????????????????//實(shí)現(xiàn)類只有一個(gè)話,直接獲取
          ????????????????????????if?(subClasses.size()?==?1)?{
          ????????????????????????????Class?aClass?=?subClasses.iterator().next();
          ????????????????????????????beanFieldInstance?=?ReflectionUtil.newInstance(aClass);
          ????????????????????????}
          ????????????????????????//實(shí)現(xiàn)類多與一個(gè)的話,根據(jù)?Qualifier?注解的值獲取
          ????????????????????????if?(subClasses.size()?>?1)?{
          ????????????????????????????Class?aClass?=?subClasses.iterator().next();
          ????????????????????????????Qualifier?qualifier?=?beanField.getDeclaredAnnotation(Qualifier.class);
          ????????????????????????????beanName?=?qualifier?==?null???aClass.getName()?:?qualifier.value();
          ????????????????????????????beanFieldInstance?=?beans.get(beanName);
          ????????????????????????}

          ????????????????????}
          ????????????????????//?如果最后獲取到的字段對(duì)象為null,就拋出異常
          ????????????????????if?(beanFieldInstance?==?null)?{
          ????????????????????????throw?new?CanNotDetermineTargetBeanException("can?not?determine?target?bean");
          ????????????????????}
          ????????????????????//通過(guò)反射設(shè)置指定對(duì)象中的指定字段的值
          ????????????????????ReflectionUtil.setField(bean,?beanField,?beanFieldInstance);
          ????????????????}
          ????????????}
          ????????});


          ????}

          ????/**
          ?????*?獲取接口對(duì)應(yīng)的實(shí)現(xiàn)類
          ?????*/

          ????@SuppressWarnings("unchecked")
          ????public?static?Set>?getSubClass(String?packageName,?Class?interfaceClass)?{
          ????????Reflections?reflections?=?new?Reflections(packageName);
          ????????return?reflections.getSubTypesOf((Class)?interfaceClass);
          ????}
          }

          閑聊

          前天晚肝到很晚,把 jsoncat(仿 Spring Boot 但不同于 Spring Boot 的一個(gè)輕量級(jí)的 HTTP 框架) 的攔截器功能重構(gòu)完善了一下。感興趣的小伙伴可以先看一下,后續(xù)會(huì)帶大家看具體實(shí)現(xiàn)過(guò)程,手把手教你實(shí)現(xiàn)(用了責(zé)任鏈模式并參考了 mybatis interceptor 插件機(jī)制的實(shí)現(xiàn))。

          jsoncat 相關(guān)文章:《手寫一個(gè)類似SpringBoot的輕量級(jí)HTTP框架》

          支持原創(chuàng)!文章有幫助可以點(diǎn)個(gè)「在看」或「分享」,我都會(huì)開心很久!

          我是Guide哥,Java后端開發(fā),會(huì)一點(diǎn)前端知識(shí),喜歡烹飪,自由的少年。一個(gè)三觀比主角還正的技術(shù)人。我們下期再見!

          瀏覽 40
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                    <th id="afajh"><progress id="afajh"></progress></th>
                    亚洲嫩穴| 中文字幕一区二区无码成人 | 91一区二区三区 | 少妇拍拍 | 豆花无码AV在线 |