20--Spring创建Bean的过程(二),无参构造函数(默认构造函数)实例化

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

上一章我们已经分析了Spring实例化bean的步骤,以及对实例化方式的解析,本章分析Spring使用无参构造函数实例化bean的过程。

在分析之前先来了解一下Spring实例化bean的策略

  • JDK的反射机制
  • CGLIB动态代理

对于反射机制,如果拿到其构造函数,参数等相关信息,就可以通过反射直接创建其实例,但是为什么Spring提供了两种实例化的方式呢,答案就是我们之前分析的方法注入。14–Spring lookup-method注入和replace-method注入(二),如果当前bean是通过lookup-method或者replace-method话,那么这时就需要用到CGLIB进行动态代理,以便在创建代理的同时将动态方法织入到类中。

Spring中的实例化策略通过InstantiationStrategy类来定义,它有两个实现类,CglibSubclassingInstantiationStrategy和SimpleInstantiationStrategy,其中前者继承了后者。对于这两个类有什么区别呢?

描述 CglibSubclassingInstantiationStrategy SimpleInstantiationStrategy
是否Spring默认实例化策略
是否支持方法注入实例化
是否反射实例化

接着上一章的分析,我们来看源码,打开AbstractAutowireCapableBeanFactory类的instantiateBean方法

protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
    try {
        Object beanInstance;
        final BeanFactory parent = this;
        // 如果权限管理器不为空,需要校验
        if (System.getSecurityManager() != null) {
            beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () ->
                    getInstantiationStrategy().instantiate(mbd, beanName, parent),
                    getAccessControlContext());
        }
        else {
            // 获取实例化策略并实例化bean
            beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
        }
        BeanWrapper bw = new BeanWrapperImpl(beanInstance);
        initBeanWrapper(bw);
        return bw;
    }
    catch (Throwable ex) {
        throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
    }
}

可以看到实例化bean的方法为instantiate,进入到SimpleInstantiationStrategy类的instantiate方法中,继续查看:

public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
    // 如果没有使用方法覆盖(replace-method或lookup-method注入),则直接使用反射创建bean的实例
    // 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 {
        // 否则必须使用CGLIB实例化策略
        // Must generate CGLIB subclass.
        return instantiateWithMethodInjection(bd, beanName, owner);
    }
}

在该方法中,Spring对使用JDK的反射实例化还是CGLIB实例化进行了判断。如果没有方法覆盖(replace-method或lookup-method注入)则使用JDK的反射机制进行实例化,如果有的话,则使用CGLIB动态代理进行实例化。

具体的实例化代码这里就不分析了,大家可以使用一个普通的bean和使用了replace-method或lookup-method注入的bean进行debug。参考14–Spring lookup-method注入和replace-method注入(二)

Spring默认构造函数的实例化还是比较简单的,下一篇我们分析对构造函数参数的解析,就比较复杂了!

猜你喜欢

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