在開始分析 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 的實體化策略委託其實現。
--- SimpleInstantiationStrategyprotected Object instantiateWithMethodInjection(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {throw new UnsupportedOperationException("Method Injection not supported in SimpleInstantiationStrategy");}--- CglibSubclassingInstantiationStrategy@Overrideprotected 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進行增強,並設定callbackEnhancer 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;}@Overridepublic 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 allif (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;}@Overridepublic 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 optimizationMethodReplacer mr = this.owner.getBean(ro.getMethodReplacerBeanName(), MethodReplacer.class);return mr.reimplement(obj, method, args);}}
透過這兩個攔截器,再加上這篇部落格:【死磕 Spring】—– IOC 之解析 bean 標簽:meta、lookup-method、replace-method,是不是一道絕佳的美食。
知識星球