【Spring】构造器的入场和推断

1  前言

Spring 帮我们创建 Bean,那么它是如何创建的呢?一种是 FactoryBean 类似提供工厂的创建,还有一种就是利用我们类的构造器进行创建。那么当我们有多个构造器的时候,它又是如何选择的呢,具体情况又是如何的,这节我们就来看看。

2  构造器的选择

2.1  选择的入场时机

我们这里先简单回顾下实例化的过程,看看他是什么时候开始进场的:

复制代码
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
    // 根据beanName以及bean定义信息得到beanClass 里边会涉及SPEL表达式的解析
    Class<?> beanClass = resolveBeanClass(mbd, beanName);
    // 权限校验什么的 不看
    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());
    }
    // 如果bean定义文件mbd提供了Supplier 这样的函数接口 就通过函数接口去创建bean
    Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
    if (instanceSupplier != null) {
        return obtainFromSupplier(instanceSupplier, beanName);
    }
    // 如果bean描述文件mbd中提供了FactoryMethod工厂方法 那么就通过FactoryMethod创建bean
    if (mbd.getFactoryMethodName() != null) {
        return instantiateUsingFactoryMethod(beanName, mbd, args);
    }
    /*
     * 加锁 多次构建同一个bean时, 无需再次推断应该使用哪种方式构造实例
     */
    boolean resolved = false;
    boolean autowireNecessary = false;
    if (args == null) {
        synchronized (mbd.constructorArgumentLock) {
            if (mbd.resolvedConstructorOrFactoryMethod != null) {
                resolved = true;
                autowireNecessary = mbd.constructorArgumentsResolved;
            }
        }
    }
    if (resolved) {
        if (autowireNecessary) {
            // 通过构造方法创建bean
            return autowireConstructor(beanName, mbd, null, null);
        }
        else {
            // 通过默认的构造方法反射创建bean
            return instantiateBean(beanName, mbd);
        }
    }
    // 由后置处理器决定返回哪些构造方法,这里就是我们本节要看的
    Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
    /*
     * 下面的条件分支条件用于判断使用什么方式构造 bean 实例,
     * 有两种方式可选 - 构造方法自动注入和默认构造方法。判断的条件由4部分综合而成,如下:
     *    条件1:ctors != null -> 后置处理器返回构造方法数组是否为空
     *    条件2:mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR
     *              -> bean 配置中的 autowire 属性是否为 constructor
     *    条件3:mbd.hasConstructorArgumentValues()
     *              -> constructorArgumentValues 是否存在元素,即 bean 配置文件中
     *                 是否配置了 <construct-arg/>
     *    条件4:!ObjectUtils.isEmpty(args)
     *              -> args 数组是否存在元素,args 是由用户调用
     *                 getBean(String name, Object... args) 传入的
     * 上面4个条件,只要有一个为 true,就会通过构造方法自动注入的方式构造 bean 实例
     */
    if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
            mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
        // 通过“构造方法自动注入”的方式构造 bean 对象
        return autowireConstructor(beanName, mbd, ctors, args);
    }
    ctors = mbd.getPreferredConstructors();
    if (ctors != null) {
        // 通过“构造方法自动注入”的方式构造 bean 对象
        return autowireConstructor(beanName, mbd, ctors, null);
    }
    // 通过“默认构造方法”的方式构造 bean 对象
    return instantiateBean(beanName, mbd);
}
复制代码

那我们继续看看决断构造器的方法:

复制代码
protected Constructor<?>[] determineConstructorsFromBeanPostProcessors(@Nullable Class<?> beanClass, String beanName)
        throws BeansException {
    // 遍历每个 SmartInstantiationAwareBeanPostProcessor 进行构造器的提取,其中有一个返回不为空就结束
    if (beanClass != null && hasInstantiationAwareBeanPostProcessors()) {
        for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
            Constructor<?>[] ctors = bp.determineCandidateConstructors(beanClass, beanName);
            if (ctors != null) {
                return ctors;
            }
        }
    }
    return null;
}    
复制代码

可以看到通过调用 SmartInstantiationAwareBeanPostProcessor 接口的 determineCandidateConstructors() 方法,以确定哪些构造方法是可用的,其中有一个返回的不为空,就返回结果。

那有哪些实现了 SmartInstantiationAwareBeanPostProcessor 接口呢,我们看看类图:

大部分基本上实现都返回的是null,我们这里只需要关注一个 AutowiredAnnotationBeanPostProcessor,也是我们本节重点要看的。

2.2  AutowiredAnnotationBeanPostProcessor

我们看看:

复制代码
// AutowiredAnnotationBeanPostProcessor
public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, final String beanName)
        throws BeanCreationException {
    // 检查类是否有 @Lookup 注解 这个注解的一个作用就是类似多例 每次都返回一个新的Bean实例
    // Let's check for lookup methods here...
    if (!this.lookupMethodsChecked.contains(beanName)) {
        if (AnnotationUtils.isCandidateClass(beanClass, Lookup.class)) {
            try {
                Class<?> targetClass = beanClass;
                do {
                    // 遍历当前类中的method,查看是否写了@Lookup方法
                    ReflectionUtils.doWithLocalMethods(targetClass, method -> {
                        Lookup lookup = method.getAnnotation(Lookup.class);
                        if (lookup != null) {
                            Assert.state(this.beanFactory != null, "No BeanFactory available");
                            // 将当前method封装成LookupOverride lookup.value()表示设置的beanName
                            LookupOverride override = new LookupOverride(method, lookup.value());
                            try {
                                RootBeanDefinition mbd = (RootBeanDefinition)
                                        this.beanFactory.getMergedBeanDefinition(beanName);
                                // 设置到BeanDefinition的methodOverrides中
                                // 后面实例化的时候会判断,如果有MethodOverrides就创建代理了
                                // 没有的话就利用原始的构造方法实例化了当然也有可能会继续创建代理
                                mbd.getMethodOverrides().addOverride(override);
                            }
                            catch (NoSuchBeanDefinitionException ex) {
                                throw new BeanCreationException(beanName,
                                        "Cannot apply @Lookup to beans without corresponding bean definition");
                            }
                        }
                    });
                    // 父类有lookup也检查一下
                    targetClass = targetClass.getSuperclass();
                }
                while (targetClass != null && targetClass != Object.class);
            }
            catch (IllegalStateException ex) {
                throw new BeanCreationException(beanName, "Lookup method resolution failed", ex);
            }
        }
        // 缓存,防止多次解析 表示该类已经检查过了lookup下次就不用检查了
        this.lookupMethodsChecked.add(beanName);
    }
    // 缓存,用于快速判断的 双重检查锁方式 经典
    // Quick check on the concurrent map first, with minimal locking.
    Constructor<?>[] candidateConstructors = this.candidateConstructorsCache.get(beanClass);
    if (candidateConstructors == null) {
        // Fully synchronized resolution now...
        synchronized (this.candidateConstructorsCache) {
            candidateConstructors = this.candidateConstructorsCache.get(beanClass);
            if (candidateConstructors == null) {
                Constructor<?>[] rawCandidates;
                try {
                    // 直接看到这里,先获取当前类 所有的构造器
                    rawCandidates = beanClass.getDeclaredConstructors();
                }
                catch (Throwable ex) {
                    throw new BeanCreationException(beanName,
                            "Resolution of declared constructors on bean Class [" + beanClass.getName() +
                            "] from ClassLoader [" + beanClass.getClassLoader() + "] failed", ex);
                }
                // 遍历构造器
                List<Constructor<?>> candidates = new ArrayList<>(rawCandidates.length);
                // 保存带有@Autowired 注解的构造器
                Constructor<?> requiredConstructor = null;
                // 默认的空参构造器
                Constructor<?> defaultConstructor = null;
                // 这个略过 没看懂 primary构造器是个什么构造器  说是跟 kotlin相关的 不看
                Constructor<?> primaryConstructor = BeanUtils.findPrimaryConstructor(beanClass);
                int nonSyntheticConstructors = 0;
                // 遍历所有的构造器
                for (Constructor<?> candidate : rawCandidates) {
                    // 区分合成构造器(由编译器生成,如匿名内部类的构造器)与用户自定义的构造器
                    if (!candidate.isSynthetic()) {
                        // 非合成构造器计数加一
                        nonSyntheticConstructors++;
                    }
                    else if (primaryConstructor != null) {
                        continue;
                    }
                    // 检查构造器上是否存在@Autowired 注解
                    MergedAnnotation<?> ann = findAutowiredAnnotation(candidate);
                    // 不存在的话,在超类中寻找匹配的构造器
                    if (ann == null) {
                        Class<?> userClass = ClassUtils.getUserClass(beanClass);
                        if (userClass != beanClass) {
                            try {
                                Constructor<?> superCtor =
                                        userClass.getDeclaredConstructor(candidate.getParameterTypes());
                                ann = findAutowiredAnnotation(superCtor);
                            }
                            catch (NoSuchMethodException ex) {
                                // Simply proceed, no equivalent superclass constructor found...
                            }
                        }
                    }
                    // 不等于空说明 有@Autowired 注解的构造器
                    if (ann != null) {
                        // 说明不能存在多个带有 required 属性的@Autowired
                        if (requiredConstructor != null) {
                            throw new BeanCreationException(beanName,
                                    "Invalid autowire-marked constructor: " + candidate +
                                    ". Found constructor with 'required' Autowired annotation already: " +
                                    requiredConstructor);
                        }
                        // 判断是否为必需构造器 也就是 required 属性是否为 true
                        // 默认的 @Autowired 注解的 required = true
                        boolean required = determineRequiredStatus(ann);
                        if (required) {
                            // 确保没有其他可选构造器与必需构造器同时存在
                            if (!candidates.isEmpty()) {
                                throw new BeanCreationException(beanName,
                                        "Invalid autowire-marked constructors: " + candidates +
                                        ". Found constructor with 'required' Autowired annotation: " +
                                        candidate);
                            }
                            requiredConstructor = candidate;
                        }
                        // 添加到候选构造器列表
                        candidates.add(candidate);
                    }
                    else if (candidate.getParameterCount() == 0) {
                        // 空参构造器
                        defaultConstructor = candidate;
                    }
                }
                // 到这里候选构造器都有哪些呢?
                // (1)只有一个 required = true 的构造器,有多个 required = true的会直接抛异常
                // (2)有一个 required = true 的,反还有其他构造器的 也会直接抛异常
                // (3)有多个 required = false 的构造器
                // 也就是有一个 required = true 的构造器或者有多个 required = false 的构造器
                // 那我们继续 如果候选构造器不为空
                if (!candidates.isEmpty()) {
                    // Add default constructor to list of optional constructors, as fallback.
                    // 没有 required = true 的构造器
                    if (requiredConstructor == null) {
                        // 并且当默认构造器不为空的情况下
                        if (defaultConstructor != null) {
                            // 把默认构造器添加到候选构造器
                            candidates.add(defaultConstructor);
                        }
                        // 默认构造器为空,并且只有一个 required = false 的构造器
                        else if (candidates.size() == 1 && logger.isInfoEnabled()) {
                            // 记录日志信息,表示在名为beanName的bean上存在构造器声明的不一致性。
                            // 具体原因是该bean存在一个被@Autowired标记的构造器,并被标记为可选的,
                            // 但实际上由于没有默认构造器作为回退选项,因此这个构造器实际上是必需的。
                            // candidates.get(0)表示获取构造器的详细信息。
                            logger.info("Inconsistent constructor declaration on bean with name '" + beanName +
                                    "': single autowire-marked constructor flagged as optional - " +
                                    "this constructor is effectively required since there is no " +
                                    "default constructor to fall back to: " + candidates.get(0));
                        }
                    }
                    // candidateConstructors 构造器列表
                    candidateConstructors = candidates.toArray(new Constructor<?>[0]);
                }
                else if (rawCandidates.length == 1 && rawCandidates[0].getParameterCount() > 0) {
                    // 如果只有一个带参数的构造器,直接使用它
                    candidateConstructors = new Constructor<?>[] {rawCandidates[0]};
                }
                // 下边这两个 primaryConstructor != null 基本没符合的 也就不会进入
                else if (nonSyntheticConstructors == 2 && primaryConstructor != null &&
                        defaultConstructor != null && !primaryConstructor.equals(defaultConstructor)) {
                    candidateConstructors = new Constructor<?>[] {primaryConstructor, defaultConstructor};
                }
                else if (nonSyntheticConstructors == 1 && primaryConstructor != null) {
                    candidateConstructors = new Constructor<?>[] {primaryConstructor};
                }
                else {
                    // 无合适的构造器,返回空数组
                    candidateConstructors = new Constructor<?>[0];
                }
                this.candidateConstructorsCache.put(beanClass, candidateConstructors);
            }
        }
    }
    // 到这里 构造器列表有哪些呢?
    return (candidateConstructors.length > 0 ? candidateConstructors : null);
}
复制代码

代码很多,大家看的过程中,要边理解边看或者看不懂的及时打断点调试,多看看就会了,可以看到前一小段,主要是处理 @Lookup注解相关的,这个注解平时用的也比较少,这里简单说下它类似多例,也就是每次都给你返回一个新的 Bean实例,知道这个即可。后大半段部分,主要是获取到当前类的所有的构造器,然后逐个判断,判断的内容主要是根据有无 @Autowired 来划分,具体划分如下:

3  小结

好啦,本节关于构造器的选择,就暂时看到这里,有理解不对的地方欢迎指正哈。

posted @   酷酷-  阅读(28)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· Obsidian + DeepSeek:免费 AI 助力你的知识管理,让你的笔记飞起来!
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
历史上的今天:
2023-06-12 【操作系统】【硬件结构】CPU 缓存一致性以及伪共享问题
2023-06-12 【操作系统】【硬件结构】如何写出让 CPU 跑得更快的代码?
2023-06-12 【操作系统】【硬件结构】磁盘比内存慢几万倍?存储器的层次结构?
2023-06-12 【操作系统】【硬件结构】CPU 是如何执行程序的?
2023-06-12 【Redis】【高可用】哨兵模式是怎么实现的?
2023-06-12 【Redis】【高可用】主从复制是怎么实现的?
点击右上角即可分享
微信分享提示