在開始分析 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 實體化的策略,根據建立物件情況的不同,提供了三種策略:無參構造方法、有參構造方法、工廠方法。如下:
public interface InstantiationStrategy {
/**
* 預設構造方法
*/
Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner)
throws BeansException;
/**
* 指定構造方法
*/
Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
Constructor> ctor, @Nullable Object... args) throws BeansException;
/**
* 工廠方法
*/
Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
@Nullable Object factoryBean, Method factoryMethod, @Nullable Object... args)
throws BeansException;
}
SimpleInstantiationStrategy
InstantiationStrategy 介面有兩個實現類:SimpleInstantiationStrategy 和 CglibSubclassingInstantiationStrategy。SimpleInstantiationStrategy 對以上三個方法都做了簡單的實現。
如果是工廠方法實體化,則直接使用反射建立物件,如下:
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
@Nullable Object factoryBean, final Method factoryMethod, @Nullable Object... args) {
try {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
ReflectionUtils.makeAccessible(factoryMethod);
return null;
});
}
else {
ReflectionUtils.makeAccessible(factoryMethod);
}
Method priorInvokedFactoryMethod = currentlyInvokedFactoryMethod.get();
try {
currentlyInvokedFactoryMethod.set(factoryMethod);
Object result = factoryMethod.invoke(factoryBean, args);
if (result == null) {
result = new NullBean();
}
return result;
}
finally {
if (priorInvokedFactoryMethod != null) {
currentlyInvokedFactoryMethod.set(priorInvokedFactoryMethod);
}
else {
currentlyInvokedFactoryMethod.remove();
}
}
}
// 省略 catch
}
如果是構造方法實體化,則是先判斷是否有 MethodOverrides,如果沒有則是直接使用反射,如果有則就需要 CGLIB 實體化物件。如下:
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
// Don't override the class with CGLIB if no overrides.
if (!bd.hasMethodOverrides()) {
Constructor> constructorToUse;
synchronized (bd.constructorArgumentLock) {
constructorToUse = (Constructor>) bd.resolvedConstructorOrFactoryMethod;
if (constructorToUse == null) {
final Class> clazz = bd.getBeanClass();
if (clazz.isInterface()) {
throw new BeanInstantiationException(clazz, "Specified class is an interface");
}
try {
if (System.getSecurityManager() != null) {
constructorToUse = AccessController.doPrivileged(
(PrivilegedExceptionAction<Constructor>>) clazz::getDeclaredConstructor);
}
else {
constructorToUse = clazz.getDeclaredConstructor();
}
bd.resolvedConstructorOrFactoryMethod = constructorToUse;
}
catch (Throwable ex) {
throw new BeanInstantiationException(clazz, "No default constructor found", ex);
}
}
}
return BeanUtils.instantiateClass(constructorToUse);
}
else {
// Must generate CGLIB subclass.
return instantiateWithMethodInjection(bd, beanName, owner);
}
}
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
final Constructor> ctor, @Nullable Object... args) {
if (!bd.hasMethodOverrides()) {
if (System.getSecurityManager() != null) {
// use own privileged to change accessibility (when security is on)
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
ReflectionUtils.makeAccessible(ctor);
return null;
});
}
return (args != null ? BeanUtils.instantiateClass(ctor, args) : BeanUtils.instantiateClass(ctor));
}
else {
return instantiateWithMethodInjection(bd, beanName, owner, ctor, args);
}
}
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 的實體化策略委託其實現。
--- SimpleInstantiationStrategy
protected Object instantiateWithMethodInjection(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
throw new UnsupportedOperationException("Method Injection not supported in SimpleInstantiationStrategy");
}
--- CglibSubclassingInstantiationStrategy
@Override
protected Object instantiateWithMethodInjection(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
return instantiateWithMethodInjection(bd, beanName, owner, null);
}
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)。
public Object instantiate(@Nullable Constructor> ctor, @Nullable Object... args) {
Class> subclass = createEnhancedSubclass(this.beanDefinition);
Object instance;
if (ctor == null) {
instance = BeanUtils.instantiateClass(subclass);
}
else {
try {
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);
}
}
//這個地方解決一個bug,bug提交報告https://jira.spring.io/browse/SPR-10785
// SPR-10785: set callbacks directly on the instance instead of in the
// enhanced class (via the Enhancer) in order to avoid memory leaks.
Factory factory = (Factory) instance;
factory.setCallbacks(new Callback[] {NoOp.INSTANCE,
new LookupOverrideMethodInterceptor(this.beanDefinition, this.owner),
new ReplaceOverrideMethodInterceptor(this.beanDefinition, this.owner)});
return instance;
}
呼叫 createEnhancedSubclass()
為提供的 BeanDefinition 建立 bean 類的增強子類。
private Class> createEnhancedSubclass(RootBeanDefinition beanDefinition) {
// cglib裡面的用法,對原始class進行增強,並設定callback
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(beanDefinition.getBeanClass());
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();
}
獲取子類增強 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()
:
public int accept(Method method) {
MethodOverride methodOverride = getBeanDefinition().getMethodOverrides().getOverride(method);
if (logger.isTraceEnabled()) {
logger.trace("Override for '" + method.getName() + "' is [" + methodOverride + "]");
}
if (methodOverride == null) {
return PASSTHROUGH;
}
else if (methodOverride instanceof LookupOverride) {
return LOOKUP_OVERRIDE;
}
else if (methodOverride instanceof ReplaceOverride) {
return METHOD_REPLACER;
}
throw new UnsupportedOperationException("Unexpected MethodOverride subclass: " +
methodOverride.getClass().getName());
}
根據 BeanDefinition 中定義的 MethodOverride 不同,傳回不同的值, 這裡傳回的 PASSTHROUGH 、LOOKUPOVERRIDE、METHODREPLACER 都是 Callbak 陣列的下標,這裡對應的陣列為 CALLBACK_TYPES 陣列,如下:
private static final Class>[] CALLBACK_TYPES = new Class>[]
{NoOp.class, LookupOverrideMethodInterceptor.class, ReplaceOverrideMethodInterceptor.class};
這裡又定義了兩個熟悉的攔截器 :LookupOverrideMethodInterceptor 和 ReplaceOverrideMethodInterceptor,兩個攔截器分別對應兩個不同的 callback 業務:
LookupOverrideMethodInterceptor
private static class LookupOverrideMethodInterceptor extends CglibIdentitySupport implements MethodInterceptor {
private final BeanFactory owner;
public LookupOverrideMethodInterceptor(RootBeanDefinition beanDefinition, BeanFactory owner) {
super(beanDefinition);
this.owner = owner;
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy mp) throws Throwable {
// Cast is safe, as CallbackFilter filters are used selectively.
LookupOverride lo = (LookupOverride) getBeanDefinition().getMethodOverrides().getOverride(method);
Assert.state(lo != null, "LookupOverride not found");
Object[] argsToUse = (args.length > 0 ? args : null); // if no-arg, don't insist on args at all
if (StringUtils.hasText(lo.getBeanName())) {
return (argsToUse != null ? this.owner.getBean(lo.getBeanName(), argsToUse) :
this.owner.getBean(lo.getBeanName()));
}
else {
return (argsToUse != null ? this.owner.getBean(method.getReturnType(), argsToUse) :
this.owner.getBean(method.getReturnType()));
}
}
}
ReplaceOverrideMethodInterceptor
private static class ReplaceOverrideMethodInterceptor extends CglibIdentitySupport implements MethodInterceptor {
private final BeanFactory owner;
public ReplaceOverrideMethodInterceptor(RootBeanDefinition beanDefinition, BeanFactory owner) {
super(beanDefinition);
this.owner = owner;
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy mp) throws Throwable {
ReplaceOverride ro = (ReplaceOverride) getBeanDefinition().getMethodOverrides().getOverride(method);
Assert.state(ro != null, "ReplaceOverride not found");
// TODO could cache if a singleton for minor performance optimization
MethodReplacer mr = this.owner.getBean(ro.getMethodReplacerBeanName(), MethodReplacer.class);
return mr.reimplement(obj, method, args);
}
}
透過這兩個攔截器,再加上這篇部落格:【死磕 Spring】—– IOC 之解析 bean 標簽:meta、lookup-method、replace-method,是不是一道絕佳的美食。