原文出自:http://cmsblogs.com
作者:作者:chenssy
在开始分析 InstantiationStrategy 之前,我们先来简单回顾下 bean 的实例化过程:
- bean 的创建,主要是 AbstractAutowireCapableBeanFactory.doCreateBean() ,在这个方法中有 bean 的实例化、属性注入和初始化过程,对于 bean 的实例化过程这是根据 bean 的类型来判断的,如果是单例模式,则直接从 factoryBeanInstanceCache 缓存中获取,否则调用 createBeanInstance() 创建。
- 在 createBeanInstance() 中,如果 Supplier 不为空,则调用 obtainFromSupplier() 实例化 bean。如果 factory 不为空,则调用 instantiateUsingFactoryMethod() 实例化 bean ,如果都不是则调用 instantiateBean() 实例化bean 。但是无论是 instantiateUsingFactoryMethod() 还是 instantiateBean() 最后都一定会调用到 InstantiationStrategy 接口的 instantiate()。
InstantiationStrategy
InstantiationStrategy 接口定义了 Spring Bean 实例化的策略,根据创建对象情况的不同,提供了三种策略:无参构造方法、有参构造方法、工厂方法。如下:
![932b16c2f619f1af2d879290dabc1448.png](https://img-blog.csdnimg.cn/img_convert/932b16c2f619f1af2d879290dabc1448.png)
SimpleInstantiationStrategy
InstantiationStrategy 接口有两个实现类:SimpleInstantiationStrategy 和 CglibSubclassingInstantiationStrategy。SimpleInstantiationStrategy 对以上三个方法都做了简单的实现。
如果是工厂方法实例化,则直接使用反射创建对象,如下:
![5e7c88cb534a1e0113c300aa1c86cb21.png](https://img-blog.csdnimg.cn/img_convert/5e7c88cb534a1e0113c300aa1c86cb21.png)
如果是构造方法实例化,则是先判断是否有 MethodOverrides,如果没有则是直接使用反射,如果有则就需要 CGLIB 实例化对象。如下:
![c55f5479fcd027f1b8e08c43ac8dc5aa.png](https://img-blog.csdnimg.cn/img_convert/c55f5479fcd027f1b8e08c43ac8dc5aa.png)
SimpleInstantiationStrategy 对 instantiateWithMethodInjection() 的实现任务交给了子类 CglibSubclassingInstantiationStrategy。
MethodOverrides
对于 MethodOverrides,如果读者是跟着小编文章一路跟过来的话一定不会陌生,在 BeanDefinitionParserDelegate 类解析 的时候是否还记得这两个方法:parseLookupOverrideSubElements() 和 parseReplacedMethodSubElements() 这两个方法分别用于解析 lookup-method 和 replaced-method。parseLookupOverrideSubElements() 源码如下:
更多关于 lookup-method 和 replaced-method 请看:【死磕 Spring】----- IOC 之解析 bean 标签:meta、lookup-method、replace-method
CGLIB 实例化策略
类 CglibSubclassingInstantiationStrategy 为 Spring 实例化 bean 的默认实例化策略,其主要功能还是对父类功能进行补充:其父类将 CGLIB 的实例化策略委托其实现。
![31f34a5fc0da26716ead59aaa3ac9978.png](https://img-blog.csdnimg.cn/img_convert/31f34a5fc0da26716ead59aaa3ac9978.png)
CglibSubclassingInstantiationStrategy 实例化 bean 策略是通过其内部类 CglibSubclassCreator 来实现的。
protected Object instantiateWithMethodInjection(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner, @Nullable Constructor> ctor, @Nullable Object... args) { return new CglibSubclassCreator(bd, owner).instantiate(ctor, args); }
创建 CglibSubclassCreator 实例然后调用其 instantiate(),该方法用于动态创建子类实例,同时实现所需要的 lookups(lookup-method、replace-method)。
![b00b751123b486318c14d3a706adf5ff.png](https://img-blog.csdnimg.cn/img_convert/b00b751123b486318c14d3a706adf5ff.png)
调用 createEnhancedSubclass() 为提供的 BeanDefinition 创建 bean 类的增强子类。
![1ef9a45df43f2e69ec3f1c8fd2584f15.png](https://img-blog.csdnimg.cn/img_convert/1ef9a45df43f2e69ec3f1c8fd2584f15.png)
获取子类增强 class 后,如果 Constructor 实例 ctr 为空,则调用默认构造函数(BeanUtils.instantiateClass())来实例化类,否则则根据构造函数类型获取具体的构造器,调用 newInstance() 实例化类。在 createEnhancedSubclass() 我们注意两行代码:
enhancer.setCallbackFilter(new MethodOverrideCallbackFilter(beanDefinition));enhancer.setCallbackTypes(CALLBACK_TYPES);
通过 MethodOverrideCallbackFilter 来定义调用 callback 类型,MethodOverrideCallbackFilter 是用来定义 CGLIB 回调过滤方法的拦截器行为,它继承 CglibIdentitySupport 实现 CallbackFilter 接口, CallbackFilter 是 CGLIB 的一个回调过滤器,CglibIdentitySupport 则为 CGLIB 提供 hashCode() 和 equals() 方法,以确保 CGLIB 不会为每个 bean 生成不同的类。MethodOverrideCallbackFilter 实现 CallbackFilter accept():
![c5f9b8b57c371529e0bf72344ef5dc75.png](https://img-blog.csdnimg.cn/img_convert/c5f9b8b57c371529e0bf72344ef5dc75.png)
根据 BeanDefinition 中定义的 MethodOverride 不同,返回不同的值, 这里返回的 PASSTHROUGH 、LOOKUP_OVERRIDE、METHOD_REPLACER 都是 Callbak 数组的下标,这里对应的数组为 CALLBACK_TYPES 数组,如下:
private static final Class>[] CALLBACK_TYPES = new Class>[] {NoOp.class, LookupOverrideMethodInterceptor.class, ReplaceOverrideMethodInterceptor.class};
这里又定义了两个熟悉的拦截器 :LookupOverrideMethodInterceptor 和 ReplaceOverrideMethodInterceptor,两个拦截器分别对应两个不同的 callback 业务:
LookupOverrideMethodInterceptor
![ec546bab2a18623041be4a4620a9cf9d.png](https://img-blog.csdnimg.cn/img_convert/ec546bab2a18623041be4a4620a9cf9d.png)
ReplaceOverrideMethodInterceptor
![53730484b9d12010358076e95226121d.png](https://img-blog.csdnimg.cn/img_convert/53730484b9d12010358076e95226121d.png)
通过这两个拦截器,再加上这篇博客:【死磕 Spring】----- IOC 之解析 bean 标签:meta、lookup-method、replace-method,是不是一道绝佳的美食。