作者:京东物流 张鼎元
1 引言
大家好,置信大家对 Spring 的底层原理都有肯定的理解,这里咱们会针对 Spring 底层原理,在海量的 Spring 源代码中进行抽丝剥茧手动实现一个 Spring 繁难版本,来促成咱们对 Spring 架构有个更深的了解,对 Spring 的罕用性能进行手写模仿实现。
2 启动 Spring
针对 Bean 的创立和获取性能,咱们来进行性能的实
首先咱们创立 JdApplicationContext 类做为 Spring 启动类,实现 bean 的加载和获取性能。
UserService 和 OrderService 类作为 Bean 的实现类,通过 JdApplicationContext 类中的 getBean 办法获取到后面两个类的实现。
- App 为启动测试类
- AppConfig 为启动配置类
注:上面的代码会顺着内容解说逐渐实现
首先创立 App 类做为入口,测试 Spring 性能。通过初始化 JdApplicationContext 类,动静加载 bean 实例。通过 getBean 办法获取 bean 实例。
创立 JdApplicationContext 类,提供获取 Bean 实例办法,通过构造函数动静初始化 bean 实例。
3 扫描类门路并缓存 BeanDefinition 数据
在 JdApplicationContext 类初始化的时候,通过 AppConfig 配置类获取类的扫描门路,在扫描门路下,找到须要创立 Bean 的类,通过标注 Component 注解的类辨认须要创立的 Bean。
通过 Component 注解辨认出的类,进行封装成 BeanDefinition. 再缓存到 beanDefinitionMap 内存中。
上述的代码中,咱们发现创立 BeanDefinition 类时,封装了 class 类,beanName,scope 三个次要属性。用于创立 bean 的时候,提供 class 类进行初始化和属性的注入,创立单例类或原型类提供数据根据。
4 初始化 Bean 和依赖注入
接下来,在下面的扫描操作实现后,所有待初始化的 bean 数据存储 beanDefinitionMap 中。咱们只须要遍历 beanDefinitionMap 数据进行一一初始化和属性的注入。
上述代码中,对 bean 进行初始化时候,从 beanDefinition 中获取要初始化的 class,通过反射机构进行无参初始化。
初始化实现后,再对有 Autowired 注解的属性进行依赖注入,Autowired 注解没有传递 value 值时默认取属性名称作为 beanName,通过 getBean 办法获取 bean 实例。
getBean 办法会通过 beanName,从 beanDefinitionMap 中获得 beanDefinition 数据。通过 beanDefinition 确认该 bean 为单例类原型类
如果为原型类,间接调用 createBean 办法进行 bean 初始化。
如果为单例类,首先从 singletonBeanMap 缓存中获取 bean 实例。如果未获取到,调用 createBean 办法获取 bean 实例,同时将已创立 bean 实例缓存到 singletonBeanMap 缓存中。
此时,在上述的性能中,依赖注入繁难版本已实现。同时咱们留神到 UserService 和 OrderService 可能会产生循环依赖的问题,在这里如何解决呢?
问题代码如下:上图就是循环依赖问题代码导致的异样。反复创立 bean 进入死循环。
在初始化 bean 和属性注入之间,咱们能够减少二级缓存作为突破口,解决死循环问题。
userService 初始化后,须要注入 orderService, 通过 getBean 办法获取,因为 orderService 没有在 singletonBeanMap 缓存中,也须要初始化并注入 userService 属性, 同时 userService 还在初始化过程中,不能缓存到 singletonBeanMap 缓存中。造成彼此循环期待属性的注入。为解决此问题,咱们只须要设立初始化过程中缓存到 creatingBeanMap 中,在 userService 初始化过后,未进行属性注入前缓存到 creatingBeanMap 中,userService 须要的 orderService 属性在创立 bean 实例过程中,优先从 creatingBeanMap 缓存中失去 userService 实例,来实现 bean 实例的创立过程。orderService 实现 bean 实例创立后,userService 也相应的实现实例创立。
5 实现 InitializingBean 接口
在 createBean 过程中,咱们能够对外提供初始化扩大接口 InitializingBean 接口。只有实现该接口,咱们就能够针对 bean 的初始化进行扩大性能实现。![]
6 实现 BeanPostProcessor 接口模仿 AOP
首先创立 BeanPostProcessor 接口,作为所有 bean 实例的对外扩大接口创立 BeanPostProcessor 接口实现类,模仿 AOP 性能,指定 userService 类进行切面。在扫描类的时候,将已实现 BeanPostProcessor 接口类缓存到 beanPostProcessorList 中。通过下面的扫描,beanPostProcessorList 已缓存所有的 BeanPostProcessor 实现类。在 createBean 的时候,对已创立的 bean 实例进行预处理扩大。通过上述代码的实现成果如下:源代码:
https://3.cn/109Aj-Zok
7 总结
在上述的解说中,咱们对 Spring 底层原理进行简略的实现,通过对类的扫描,注解标识的判断,beanDefinition 的定义和缓存。通过反射和代理进行 bean 实例的创立和扩大。置信大家也看进去在实现过程中,有很多中央须要改良,还能够持续扩大 Spring 很多其它性能。例如扩大 beanDefinition 的注册,引入 Bean 工厂,提早加载等。