本文主要基于 Spring 5.0.6.RELEASE
摘要: 原创出处 http://cmsblogs.com/?p=todo 「小明哥」,谢谢!
作为「小明哥」的忠实读者,「老艿艿」略作修改,记录在理解过程中,参考的资料。
在开始分析 InstantiationStrategy 之前,我们先来简单回顾下 Bean 的实例化过程:
- Bean 的创建,主要是
AbstractAutowireCapableBeanFactory#doCreateBean(...)
方法。在这个方法中有 Bean 的实例化、属性注入和初始化过程,对于 Bean 的实例化过程这是根据 Bean 的类型来判断的,如果是单例模式,则直接从factoryBeanInstanceCache
缓存中获取,否则调用#createBeanInstance(...)
方法来创建。 - 在
#createBeanInstance(...)
方法中,如果 Supplier 不为空,则调用#obtainFromSupplier(...)
实例化 bean。如果factory
不为空,则调用#instantiateUsingFactoryMethod(...)
方法来实例化 Bean 。如果都不是,则调用#instantiateBean(...)
方法来实例化 Bean 。但是无论是#instantiateUsingFactoryMethod(...)
方法,还是#instantiateBean()
方法,最后都一定会调用到 InstantiationStrategy 接口的#instantiate(...)
方法。
1. InstantiationStrategy
InstantiationStrategy 接口定义了 Spring Bean 实例化的策略,根据创建对象情况的不同,提供了三种策略:无参构造方法、有参构造方法、工厂方法。代码如下:
public interface InstantiationStrategy { |
2. SimpleInstantiationStrategy
InstantiationStrategy 接口有两个实现类:SimpleInstantiationStrategy 和 CglibSubclassingInstantiationStrategy。
SimpleInstantiationStrategy 对以上三个方法都做了简单的实现。
① 如果是工厂方法实例化,则直接使用反射创建对象,如下:
// SimpleInstantiationStrategy.java |
② 如果是构造方法实例化,则是先判断是否有 MethodOverrides,如果没有则是直接使用反射,如果有则就需要 CGLIB 实例化对象。如下:
// SimpleInstantiationStrategy.java |
- SimpleInstantiationStrategy 对
#instantiateWithMethodInjection(RootBeanDefinition bd, String beanName, BeanFactory owner, Constructor<?> ctor, Object... args)
的实现任务交给了子类 CglibSubclassingInstantiationStrategy 。
3. MethodOverrides
对于 MethodOverrides,如果读者是跟着小编文章一路跟过来的话一定不会陌生,在 BeanDefinitionParserDelegate 类解析 <bean/>
的时候是否还记得这两个方法:#parseLookupOverrideSubElements(...)
和 #parseReplacedMethodSubElements(...)
这两个方法分别用于解析 lookup-method
和 replaced-method
属性。
其中,#parseLookupOverrideSubElements(...)
源码如下:
parseLookupOverrideSubElements
更多关于 lookup-method
和 replaced-method
请看:【死磕 Spring】—– IoC 之解析 bean 标签:meta、lookup-method、replace-method
4. CglibSubclassingInstantiationStrategy
类 CglibSubclassingInstantiationStrategy 为 Spring 实例化 Bean 的默认实例化策略,其主要功能还是对父类功能进行补充:其父类将 CGLIB 的实例化策略委托其实现。
// SimpleInstantiationStrategy.java |
CglibSubclassingInstantiationStrategy 实例化 Bean 策略,是通过其内部类 CglibSubclassCreator 来实现的。代码如下:
// CglibSubclassingInstantiationStrategy.java
protected Object instantiateWithMethodInjection(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner, @Nullable Constructor<?> ctor, Object... args) {
// Must generate CGLIB subclass...
// 通过CGLIB生成一个子类对象
return new CglibSubclassCreator(bd, owner).instantiate(ctor, args);
}创建 CglibSubclassCreator 实例,然后调用其
#instantiate(Constructor<?> ctor, Object... args)
方法,该方法用于动态创建子类实例,同时实现所需要的 lookups(lookup-method
、replace-method
)。// CglibSubclassingInstantiationStrategy.java#CglibSubclassCreator
public Object instantiate(@Nullable Constructor<?> ctor, Object... args) {
// <x> 通过 Cglib 创建一个代理类
Class<?> subclass = createEnhancedSubclass(this.beanDefinition);
Object instance;
// <y> 没有构造器,通过 BeanUtils 使用默认构造器创建一个bean实例
if (ctor == null) {
instance = BeanUtils.instantiateClass(subclass);
} else {
try {
// 获取代理类对应的构造器对象,并实例化 bean
Constructor<?> enhancedSubclassConstructor = subclass.getConstructor(ctor.getParameterTypes());
instance = enhancedSubclassConstructor.newInstance(args);
} catch (Exception ex) {
throw new BeanInstantiationException(this.beanDefinition.getBeanClass(),
"Failed to invoke constructor for CGLIB enhanced subclass [" + subclass.getName() + "]", ex);
}
}
// SPR-10785: set callbacks directly on the instance instead of in the
// enhanced class (via the Enhancer) in order to avoid memory leaks.
// 为了避免 memory leaks 异常,直接在 bean 实例上设置回调对象
Factory factory = (Factory) instance;
factory.setCallbacks(new Callback[] {NoOp.INSTANCE,
new LookupOverrideMethodInterceptor(this.beanDefinition, this.owner),
new ReplaceOverrideMethodInterceptor(this.beanDefinition, this.owner)});
return instance;
}在
<x>
处,调用#createEnhancedSubclass(RootBeanDefinition beanDefinition)
方法,为提供的 BeanDefinition 创建 bean 类的增强子类。代码如下:// CglibSubclassingInstantiationStrategy.java#CglibSubclassCreator
private Class<?> createEnhancedSubclass(RootBeanDefinition beanDefinition) {
// 创建 Enhancer 对象
Enhancer enhancer = new Enhancer();
// 设置 Bean 类
enhancer.setSuperclass(beanDefinition.getBeanClass());
// 设置 Spring 的命名策略
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
// 设置生成策略
if (this.owner instanceof ConfigurableBeanFactory) {
ClassLoader cl = ((ConfigurableBeanFactory) this.owner).getBeanClassLoader();
enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(cl));
}
// 过滤,自定义逻辑来指定调用的callback下标
enhancer.setCallbackFilter(new MethodOverrideCallbackFilter(beanDefinition));
enhancer.setCallbackTypes(CALLBACK_TYPES);
return enhancer.createClass();
}- CGLIB 的标准 API 的使用。
<y>
处,获取子类增强subclass
后,如果 Constructor 实例ctr
为空,则调用默认构造函数(BeanUtils#instantiateClass(subclass)
)来实例化类,否则则根据构造函数类型获取具体的构造器,调用Constructor#newInstance(args)
方法来实例化类。
4.1 MethodOverrideCallbackFilter
在 <x>
处调用的 #createEnhancedSubclass(RootBeanDefinition beanDefinition)
方法,我们注意两行代码:
// CglibSubclassingInstantiationStrategy.java#CglibSubclassCreator |
- 通过 MethodOverrideCallbackFilter 来定义调用 callback 类型。
MethodOverrideCallbackFilter 是用来定义 CGLIB 回调过滤方法的拦截器行为,它继承 CglibIdentitySupport 实现 CallbackFilter 接口。
- CallbackFilter 是 CGLIB 的一个回调过滤器。
- CglibIdentitySupport 则为 CGLIB 提供
#hashCode()
和#equals(Object o)
方法,以确保 CGLIB 不会为每个 Bean 生成不同的类。
MethodOverrideCallbackFilter 实现 CallbackFilter 的 #accept(Method method)
方法,代码如下:
// CglibSubclassingInstantiationStrategy.java#MethodOverrideCallbackFilter |
根据 BeanDefinition 中定义的 MethodOverride 不同,返回不同的值, 这里返回的
PASSTHROUGH
、LOOKUP_OVERRIDE
、METHOD_REPLACER
都是 Callback 数组的下标,这里对应的数组为CALLBACK_TYPES
数组,如下:// CglibSubclassingInstantiationStrategy.java#CglibSubclassCreator
private static final Class<?>[] CALLBACK_TYPES = new Class<?>[] {
NoOp.class,
LookupOverrideMethodInterceptor.class,
ReplaceOverrideMethodInterceptor.class
};- 这里又定义了两个熟悉的拦截器 :LookupOverrideMethodInterceptor 和 ReplaceOverrideMethodInterceptor,两个拦截器分别对应两个不同的 callback 业务。详细解析,见 「4.2 LookupOverrideMethodInterceptor」 和 「4.3 ReplaceOverrideMethodInterceptor」 中。
4.2 LookupOverrideMethodInterceptor
// CglibSubclassingInstantiationStrategy.java#LookupOverrideMethodInterceptor |
4.3 ReplaceOverrideMethodInterceptor
// CglibSubclassingInstantiationStrategy.java#ReplaceOverrideMethodInterceptor |
通过这两个拦截器,再加上这篇博客:【死磕 Spring】—— IoC 之解析 bean 标签:meta、lookup-method、replace-method,是不是一道绝佳的美食。