上一节分析了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的默认策略。
- 反射机制和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的反射机制。我们回到测试类中。查看生成的实例。
-
查看实例信息:
-
实例详细信息
当代码运行到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。