上一节分析了Spring实例化单例bean的准备工作,而且已经接触到了真正创建bean的方法doCreateBean,本小节分析Spring是如何实例化bean的。
引言,doCreateBean方法简析
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException { // Instantiate the bean. // ① 实例化bean BeanWrapper instanceWrapper = null; // 注意factoryBeanInstanceCache是ConcurrentMap,remove方法会返回删除的键值(如果不存在返回null) if (mbd.isSingleton()) { instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); } // 如果factoryBeanInstanceCache没有缓存对应的BeanWrapper,则重新创建bean实例 if (instanceWrapper == null) { instanceWrapper = createBeanInstance(beanName, mbd, args); } final Object bean = instanceWrapper.getWrappedInstance(); Class<?> beanType = instanceWrapper.getWrappedClass(); if (beanType != NullBean.class) { mbd.resolvedTargetType = beanType; } // Allow post-processors to modify the merged bean definition. // ② 允许MergedBeanDefinitionPostProcessor后处理器修改已合并的bean定义。 synchronized (mbd.postProcessingLock) { if (!mbd.postProcessed) { try { applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName); } catch (Throwable ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Post-processing of merged bean definition failed", ex); } mbd.postProcessed = true; } } // Eagerly cache singletons to be able to resolve circular references // even when triggered by lifecycle interfaces like BeanFactoryAware. // ③ 提前缓存ObjectFactory以解决bean之间的循环依赖 // mbd.isSingleton()->是否单例 // allowCircularReferences->是否允许循环依赖 // isSingletonCurrentlyInCreation->该bean是否创建中 boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) { addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); } // Initialize the bean instance. // ④ 初始化bean实例 这里大家要与第①步区分开,到这里bean已经完成了实例化,但是还没有完成初始化的操作,例如bean的属性填充 Object exposedObject = bean; try { // 填充bean属性 populateBean(beanName, mbd, instanceWrapper); // 初始化bean exposedObject = initializeBean(beanName, exposedObject, mbd); } catch (Throwable ex) { if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) { throw (BeanCreationException) ex; } else { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex); } } // ⑤ 循环依赖检查 if (earlySingletonExposure) { Object earlySingletonReference = getSingleton(beanName, false); if (earlySingletonReference != null) { if (exposedObject == bean) { exposedObject = earlySingletonReference; } else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) { String[] dependentBeans = getDependentBeans(beanName); Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length); for (String dependentBean : dependentBeans) { if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) { actualDependentBeans.add(dependentBean); } } if (!actualDependentBeans.isEmpty()) { throw new BeanCurrentlyInCreationException(beanName, "Bean with name '" + beanName + "' has been injected into other beans [" + StringUtils.collectionToCommaDelimitedString(actualDependentBeans) + "] in its raw version as part of a circular reference, but has eventually been " + "wrapped. This means that said other beans do not use the final version of the " + "bean. This is often the result of over-eager type matching - consider using " + "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example."); } } } } // Register bean as disposable. try { // ⑥ 根据bean的作用域注册bean registerDisposableBeanIfNecessary(beanName, bean, mbd); } catch (BeanDefinitionValidationException ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex); } // ⑦ 返回bean实例 return exposedObject; }
步骤如下:
- ① 实例化bean
- ② 允许MergedBeanDefinitionPostProcessor后处理器修改已合并的bean定义。
- ③ 提前缓存ObjectFactory以解决bean之间的循环依赖
- ④ 初始化bean实例 这里大家要与第①步区分开,到这里bean已经完成了实例化,但是还没有完成初始化的操作,例如bean的属性填充
- ⑤ 循环依赖检查
- ⑥ 根据bean的作用域注册bean
- ⑦ 返回bean实例
这些步骤中涉及的知识点很多,我们逐步分析。
1.实例化bean
createBeanInstance方法完成了对bean的实例化操作,打开该方法。
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) { // 确保此时beanClass已经被解析 Class<?> beanClass = resolveBeanClass(mbd, beanName); // beanClass不为空,且beanClass的修饰符为不为public,且不允许访问非公共构造函数和方法,则抛出异常 if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Bean class isn't public, and non-public access not allowed: " + beanClass.getName()); } // ① Spring5.0新增的实例化策略,如果设置了该策略,将会覆盖构造方法和工厂方法实例化策略 Supplier<?> instanceSupplier = mbd.getInstanceSupplier(); if (instanceSupplier != null) { return obtainFromSupplier(instanceSupplier, beanName); } // ② 如果有工厂方法的话,则使用工厂方法实例化bean if (mbd.getFactoryMethodName() != null) { return instantiateUsingFactoryMethod(beanName, mbd, args); } // ③ 当创建一个相同的bean时,使用之间保存的快照 // 这里可能会有一个疑问,什么时候会创建相同的bean呢? // ③-->① 单例模式: Spring不会缓存该模式的实例,那么对于单例模式的bean,什么时候会用到该实例化策略呢? // 我们知道对于IoC容器除了可以索取bean之外,还能销毁bean,当我们调用xmlBeanFactory.destroyBean(myBeanName,myBeanInstance), // 销毁bean时,容器是不会销毁已经解析的构造函数快照的,如果再次调用xmlBeanFactory.getBean(myBeanName)时,就会使用该策略了. // ③-->② 原型模式: 对于该模式的理解就简单了,IoC容器不会缓存原型模式bean的实例,当我们第二次向容器索取同一个bean时,就会使用该策略了. boolean resolved = false; boolean autowireNecessary = false; if (args == null) { synchronized (mbd.constructorArgumentLock) { if (mbd.resolvedConstructorOrFactoryMethod != null) { resolved = true; autowireNecessary = mbd.constructorArgumentsResolved; } } } // 如果该bean已经被解析过 if (resolved) { // 使用已经解析过的构造函数实例化 if (autowireNecessary) { return autowireConstructor(beanName, mbd, null, null); } // 使用默认无参构造函数实例化 else { return instantiateBean(beanName, mbd); } } // ④ 确定需要使用的构造函数 Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName); if (ctors != null || mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR || mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) { return autowireConstructor(beanName, mbd, ctors, args); } // ⑤ 无任何的特殊处理,则使用默认的无参构造函数实例化bean return instantiateBean(beanName, mbd); }
从该方法里我们看到了Spring实例化bean的策略:
- 工厂方法(实例工厂和静态工厂)
- 构造函数实例化(无参构造和有参构造)
- 通过实例提供者实例化(Spring5新增的实例化策略)
先从最简单的无参构造函数实例化分析,因为其他的实例化策略,如有参构造函数实例化会涉及到构造函数解析,该过程也是非常复杂,所以先分析最简单的无参构造函数实例化。也就是createBeanInstance方法中的第五步,历经前几个步骤的处理之后仍然无法实例化bean并返回其实例的话,那么就采用默认构造函数实例化。
2.默认构造函数实例化Bean
protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) { try { Object beanInstance; final BeanFactory parent = this; // 1、如果权限管理器不为空,需要校验 if (System.getSecurityManager() != null) { beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () -> getInstantiationStrategy().instantiate(mbd, beanName, parent), getAccessControlContext()); } else { // 2、获取实例化策略并实例化bean beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent); } // 3、实例并初始化BeanWrapper对象 BeanWrapper bw = new BeanWrapperImpl(beanInstance); initBeanWrapper(bw); return bw; } catch (Throwable ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex); } }
- 获取实例化策略
创建一个类的实例对象除了通过new关键字之外,还可以通过JDK的反射机制
或CGLIB动态代理
来创建对象实例,这也是Spring实例化bean的两种策略。所以首先通过getInstantiationStrategy方法来获取实例化bean的策略。从下图中可以看到,如果无特殊配置,Spring将采用CGLIB动态代理机制作为实例化bean的默认策略。
image.png
- 反射机制和CGLIB使用时机
Spring何时使用反射何时使用CGLIB创建bean的实例呢?答案很简单,如果没有使用方法覆盖(replace-method或lookup-method注入),则直接使用反射创建bean的实例;否则必须使用CGLIB机制。Spring通过instantiate方法来确定具体使用哪种机制。
3. instantiate方法获取实例化机制
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) { // 1、如果没有使用方法覆盖(replace-method或lookup-method注入),则直接使用反射创建bean的实例 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 { // 未能获取到已经解析过的构造方法,则通过getDeclaredConstructor方法获取构造方法 constructorToUse = clazz.getDeclaredConstructor(); } bd.resolvedConstructorOrFactoryMethod = constructorToUse; } catch (Throwable ex) { throw new BeanInstantiationException(clazz, "No default constructor found", ex); } } } // 通过BeanUtils类实例化bean return BeanUtils.instantiateClass(constructorToUse); } // 2、否则必须使用CGLIB实例化策略 else { return instantiateWithMethodInjection(bd, beanName, owner); } }
判断的方式很简单,通过BeanDefinition判断有没有replace-method或lookup-method注入即可;如果没有则默认使用反射机制实例化bean,否则必须使用CGLIB实例bean。
4.反射机制实例化bean
public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException { try { ReflectionUtils.makeAccessible(ctor); // KotlinDetector,Spring5.0新增的类,用于检测Kotlin的存在和识别Kotlin类型。 return (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(ctor.getDeclaringClass()) ? KotlinDelegate.instantiateClass(ctor, args) : ctor.newInstance(args)); } catch (InstantiationException ex) { throw new BeanInstantiationException(ctor, "Is it an abstract class?", ex); } catch (IllegalAccessException ex) { throw new BeanInstantiationException(ctor, "Is the constructor accessible?", ex); } catch (IllegalArgumentException ex) { throw new BeanInstantiationException(ctor, "Illegal arguments for constructor", ex); } catch (InvocationTargetException ex) { throw new BeanInstantiationException(ctor, "Constructor threw exception", ex.getTargetException()); } }
通过ctor.newInstance(args)
方法创建了Bean的实例,后续代码已经属于JDK源码,感兴趣的同学可以自行分析。
5.CGLIB实例bean
打开我们之前分析的test9(测试replace-method注入)和test10(测试replace-method注入),分析CGLIB实例化。传送:07--lookup-method和replace-method注入,这里我们只分析一下replace_method方法。
@Override protected Object instantiateWithMethodInjection(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) { return instantiateWithMethodInjection(bd, beanName, owner, null); }
@Override protected Object instantiateWithMethodInjection(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner, @Nullable Constructor<?> ctor, @Nullable Object... args) { // Must generate CGLIB subclass... return new CglibSubclassCreator(bd, owner).instantiate(ctor, args); }
public Object instantiate(@Nullable Constructor<?> ctor, @Nullable Object... args) { // 1、生成增强子类 Class<?> subclass = createEnhancedSubclass(this.beanDefinition); Object instance; // 2、实例化增强子类 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); } } // 3、设置回调 // 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; }
对于增强子类的实例化,依然采用了jdk的反射机制。我们回到测试类中。查看生成的实例。
- 查看实例信息:
image.png - 实例详细信息
image.png
当代码运行到originalDog.sayHello("输出结果已经被替换了。。。");
时,会被CglibSubclassingInstantiationStrategy类的intercept方法拦截。
public Object intercept(Object obj, Method method, Object[] args, MethodProxy mp) throws Throwable { // 1、获取覆盖方法信息 ReplaceOverride ro = (ReplaceOverride) getBeanDefinition().getMethodOverrides().getOverride(method); Assert.state(ro != null, "ReplaceOverride not found"); // TODO could cache if a singleton for minor performance optimization // 2、实例化覆盖方法 MethodReplacer mr = this.owner.getBean(ro.getMethodReplacerBeanName(), MethodReplacer.class); // 3、调用覆盖方法 return mr.reimplement(obj, method, args); }
当代码执行到第三步时就会调用reimplement方法了。
/** * @author: LiYanChao * @create: 2018-09-06 00:02 */ public class ReplaceDog implements MethodReplacer { @Override public Object reimplement(Object obj, Method method, Object[] args) throws Throwable { System.out.println("Hello, I am a white dog..."); Arrays.stream(args).forEach(str -> System.out.println("参数:" + str)); return obj; } }
6.总结
到这里通过无参构造方法实例化bean就分析完了,这里大家需要记住Spring实例化bean的方式以及何时使用何种方式。如果使用了replace-method或lookup-method注入,则直接使用CGLIB实例化bean,否则直接使用反射实例化bean。