1. 1 不可撤销
  2. 2 小年兽 程嘉敏
  3. 3 手放开 李圣杰
  4. 4 迷人的危险3(翻自 dance flow) FAFA
  5. 5 山楂树之恋 程佳佳
  6. 6 summertime cinnamons / evening cinema
  7. 7 不谓侠(Cover 萧忆情Alex) CRITTY
  8. 8 神武醉相思(翻自 优我女团) 双笙
  9. 9 空山新雨后 音阙诗听 / 锦零
  10. 10 Wonderful U (Demo Version) AGA
  11. 11 广寒宫 丸子呦
  12. 12 陪我看日出 回音哥
  13. 13 春夏秋冬的你 王宇良
  14. 14 世界が终わるまでは… WANDS
  15. 15 多想在平庸的生活拥抱你 隔壁老樊
  16. 16 千禧 徐秉龙
  17. 17 我的一个道姑朋友 双笙
  18. 18 大鱼  (Cover 周深) 双笙
  19. 19 霜雪千年(Cover 洛天依 / 乐正绫) 双笙 / 封茗囧菌
  20. 20 云烟成雨(翻自 房东的猫) 周玥
  21. 21 情深深雨濛濛 杨胖雨
  22. 22 Five Hundred Miles Justin Timberlake / Carey Mulligan / Stark Sands
  23. 23 斑马斑马 房东的猫
  24. 24 See You Again Wiz Khalifa / Charlie Puth
  25. 25 Faded Alan Walker / Iselin Solheim
  26. 26 Natural J.Fla
  27. 27 New Soul Vox Angeli
  28. 28 ハレハレヤ(朗朗晴天)(翻自 v flower) 猫瑾
  29. 29 像鱼 王贰浪
  30. 30 Bye Bye Bye Lovestoned
  31. 31 Blame You 眠 / Lopu$
  32. 32 Believer J.Fla
  33. 33 书信 戴羽彤
  34. 34 柴 鱼 の c a l l i n g【已售】 幸子小姐拜托了
  35. 35 夜空中最亮的星(翻自 逃跑计划) 戴羽彤
  36. 36 慢慢喜欢你 LIve版(翻自 莫文蔚) 戴羽彤
  37. 37 病变(翻自 cubi) 戴羽彤
  38. 38 那女孩对我说 (完整版) Uu
  39. 39 绿色 陈雪凝
  40. 40 月牙湾 LIve版(翻自 F.I.R.) 戴羽彤
夜空中最亮的星(翻自 逃跑计划) - 戴羽彤
00:00 / 04:10

夜空中最亮的星 能否听清

那仰望的人 心底的孤独和叹息

夜空中最亮的星 能否记起

那曾与我同行 消失在风里的身影

我祈祷拥有一颗透明的心灵

和会流泪的眼睛

给我再去相信的勇气

越过谎言去拥抱你

每当我找不到存在的意义

每当我迷失在黑夜里

噢喔喔 夜空中最亮的星

请指引我靠近你

夜空中最亮的星 是否知道

那曾与我同行的身影 如今在哪里

夜空中最亮的星 是否在意

是等太阳先升起 还是意外先来临

我宁愿所有痛苦都留在心底

也不愿忘记你的眼睛

哦 给我再去相信的勇气

哦 越过谎言去拥抱你

每当我找不到存在的意义

每当我迷失在黑夜里

噢喔喔 夜空中最亮的星

请照亮我向前行 哒~

我祈祷拥有一颗透明的心灵

和会流泪的眼睛 哦

给我再去相信的勇气

哦 越过谎言去拥抱你

每当我找不到存在的意义

每当我迷失在黑夜里

噢喔喔 夜空中最亮的星

请照亮我向前行

手写web服务器:定义Autorwired注解,实现属性自动注入

前言

昨天,我们已经解决了post请求的阻塞问题,所以我们今天又可以继续搞事情了,今天我们要实现的也是spring中很核心的注解——Autowired。这个注解想必大家肯定不陌生,在spring项目中,我们经常用它来为我们的属性注入值,实现属性的自动装配。

好了,话不多说,我们来看具体如何实现.

实现过程

定义注解

这一块就很简单了,前面我们也不止一次写过,这里target指定的是属性

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

加到属性上

直接把@Autowired注解加在我们要注入的属性上

优化扫描方法

属性是在类初始化的时候,自动被赋值的,所以我们要调整初始化流程

private static void initRequestMappingMap() {
        logger.info("start to scanRequestMapping, controllerSet = {}", classSet);
        if (classSet == null) {
            return;
        }
        classSet.forEach(aClass -> {
            Annotation controller = aClass.getAnnotation(Controller.class);
            if (Objects.isNull(controller)) {
                return;
            }
            Method[] methods = aClass.getDeclaredMethods();
            for (Method method : methods) {
                RequestMapping annotation = method.getAnnotation(RequestMapping.class);
                if (Objects.nonNull(annotation)) {
                    requestMappingMap.put(annotation.value(), method);
                }
            }
            Field[] fields = aClass.getDeclaredFields();
            try {
                Object o = aClass.newInstance();
                for (Field field : fields) {
                    Autowired annotation = field.getAnnotation(Autowired.class);
                    if (Objects.nonNull(annotation)) {
                        field.setAccessible(true);
                        field.set(o, contentMap.get(field.getType().getName()));
                    }
                }
                contentMap.put(aClass.getName(), o);
            } catch (InstantiationException e) {
                logger.error("初始controller失败:", e);
            } catch (IllegalAccessException e) {
                logger.error("初始controller失败:", e);
            }
        });
        logger.info("scanRequestMapping end, requestMappingMap = {}", requestMappingMap);
    }

我们在初始化这里加了一段字段初始化的代码,上面是完整代码,字段初始化只有短短几行:

Field[] fields = aClass.getDeclaredFields();
try {
    Object o = aClass.newInstance();
    for (Field field : fields) {
        Autowired annotation = field.getAnnotation(Autowired.class);
        if (Objects.nonNull(annotation)) {
            field.setAccessible(true);
            field.set(o, contentMap.get(field.getType().getName()));
        }
    }
    contentMap.put(aClass.getName(), o);
} catch (InstantiationException e) {
    logger.error("初始controller失败:", e);
} catch (IllegalAccessException e) {
    logger.error("初始controller失败:", e);
}

这里需要注意的是,因为属性是私有的,必须通过getDeclaredFields获取属性值,getFields方法是没办法拿到私有属性的;

另外一个需要注意的点是,私有属性必须通过setAccessible设置为可访问才可以,否则会报错:

因为字段赋值是基于对象实例的,所以我们要先创建类的实例:

Object o = aClass.newInstance()

然后通过field.set给属性赋值,这里赋值要通过IOC容器拿到赋值对象的实例,所以被赋值属性的实例必须先初始化,否则会有问题。

同时,我们把带有@Autowired注解的类的实例也存进了IOC容器,这样在后面调用controller对用mapping方法的时候,我们直接从ioc容器中拿出来即可:

Object o = contentMap.get(declaringClass.getName());
Object invoke = method.invoke(o, parameters);

这是因为如果你在调用的时候再去创建实例,这时候属性也要赋值,否则会报错的,所以初始化的时候直接创建实例是比较合理的方式。

测试

浏览器调用下试下:

可以看到,我们调用的时候,service已经有值了,方法调用完成后,结果正常返回:

总结

好了,今天的内容到这里就结束了。在上面的内容中,我们展示了@Autowired注解的定义、具体的应用,以及Ioc对于Autowired注解的处理过程,最后我们经过测试,结果与预期一致,当然具体springboot是如何实现的,还需要进一步的研究和探讨,我这里分享的是自己的实现思路,感兴趣的小伙伴可以自己动手试下。

下面是项目的开源仓库,有兴趣的小伙伴可以去看看,如果有想法的小伙伴,我真心推荐你自己动个手,自己写一下,真的感觉不错:

https://github.com/Syske/syske-boot

posted @ 2021-06-09 13:36  云中志  阅读(108)  评论(0编辑  收藏  举报