21--Spring通过无参构造方法实例化单例bean

版权声明:如有转载,请标明出处,谢谢合作! https://blog.csdn.net/lyc_liyanchao/article/details/83049779

上一节分析了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的反射机制。我们回到测试类中。查看生成的实例。

扫描二维码关注公众号,回复: 3673802 查看本文章
  • 查看实例信息:
    在这里插入图片描述
  • 实例详细信息
    在这里插入图片描述

当代码运行到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。

猜你喜欢

转载自blog.csdn.net/lyc_liyanchao/article/details/83049779