作者:京东物流 张鼎元
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工厂,提早加载等。
发表回复