TDD 的难点首先在于理解需求,并将需求分解为功能点
RESTful API 的开发框架
- 场景:支撑 RESTful API 的开发框架,可以想象成下面两个场景
- mini 版本的 Dropwizard
- Spring MVC
- 功能
- 一个依赖注入容器(Dependency Injection Container/IoC Container)
- 一个支持 RESTful API 构建的 Web 框架
- 目标:以 Jakarta EE 中的 Jakarta Dependency Injection 和 Jakarta RESTful Web Services 为主要功能参考,并对其适当简化
依赖注入容器的大致功能
- 关于依赖注入的来龙去脉可以参看 Martin Fowler 在 2004 年写的文章 《IoC 容器与依赖注入模式》
- Jakarta Dependency Injection 的功能主要分为四部分:
- 组件的构造
- 依赖注入方法
- Constructor 注入
- Field 注入
- 方法注入
- 依赖的选择
- 生命周期控制
- 容器上下文
- 通过 tag 来区分不同的对象
- 弱类型,重构时需要基于字符串查找
- 自定义 Annotation
- 强类型,对重构更友好
- 通过 tag 来区分不同的对象
- Scope 判断
- 单例
- 多例
相关技术
需要注意的问题
有依赖关系时的注入
两个构造器间的循环依赖
|
|
JSR330 中的解决方案:通过标准的接口实现注入
|
|
进阶功能
- 配置容器如何配置(可用 DSL 实现可配置的依赖注入)
- 容器层级结构(Scope 上下文隔离)
- 生命周期回调
功能点分解
happy path
自定义依赖注入的 Annotation
- @Inject:标识这个类可以被容器管理(类似 Spring 的 @Component)
- @Named:可以设置 String 类型的 tag 做唯一标识
- @Scope:标识容器创建的对象是单例、多例的标签
- 支持自定义 Annotation 被容器加入依赖管理(组合 @Inject、@Named、@Scope 实现自定义功能)
- @Constructor:Constructor 注入标签
- @Field:Field 注入标签
- @Method:方法注入标签
将标记的类找到备用
- 扫描项目中所有的类
- 提取出所有标记了依赖注入标签的类的信息
- 类名称
- 类的完整路径
- 类的所有构造器
- 类上的所有 Annotation
- 字段上的所有 Annotation
- 方法上的所有 Annotation
- 解析容器支持的自定义 Annotation
- 将自定义 Annotation 转换为普通的 Annotation
- 收集容器相关的 Annotation 类的信息
- 将这些类的信息存储在容器中
代理类
- 通过代理类实现 Provided 解决循环依赖问题
通过容器获取实例
- 根据 Class 在容器中找到对应的类,返回实例
- 根据 @Named 中的 tag,找到对应的类,返回实例
- 根据 自定义 Annotation 找到对应的类,返回实例
- 利用反射注入:Field 实例
- 利用反射注入:方法参数实例
default path
- @Named:默认去类名(首字母小写)
- @Scope:默认为多例
sad path
没有匹配到对象
- Class 没有被容器管理
- @Named 没有匹配的字符串
- 不同包下,类名一样
- 多个 @Named 重名
- 不支持第三方 jar 中类由容器统一管理
单例模式下创建对象需要考虑内存消耗、线程安全的问题