手写模拟Spring底层原理-Bean的创建与获取
作者:京东物流 张鼎元
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实例进行预处理扩展。 通过上述代码的实现效果如下: 源代码:
7 总结
在上述的讲解中,我们对Spring底层原理进行简单的实现,通过对类的扫描,注解标识的判断,beanDefinition的定义和缓存。通过反射和代理进行bean实例的创建和扩展。相信大家也看出来在实现过程中,有很多地方需要改进,还可以继续扩展Spring很多其它功能。例如扩展beanDefinition的注册,引入Bean工厂,延迟加载等。