扩展点系列之SmartInstantiationAwareBeanPostProcessor确定执行哪一个构造方法 - 第432篇

导读

一、SmartInstantiationAwareBeanPostProcessor概述

1.1是什么?

SmartInstantiationAwareBeanPostProcessor 继承自InstantiationAwareBeanPostProcessor;

但是SmartInstantiationAwareBeanPostProcessor多了一个三个方法。

1.2三个方法详解

(1)getEarlyBeanReference

获得提前暴露的bean引用,主要用于解决循环引用的问题。

getEarlyBeanReference:该触发点发生在postProcessAfterInstantiation之后,当有循环依赖的场景,当bean实例化好之后,为了防止有循环依赖,会提前暴露回调方法,用于bean实例化的后置处理。这个方法就是在提前暴露的回调方法中触发。

(2)determineCandidateConstructors

检测Bean的构造器,可以检测出多个候选构造器,再有相应的策略决定使用哪一个,如AutowiredAnnotationBeanPostProcessor实现将自动扫描通过@Autowired/@Value注解的构造器从而可以完成构造器注入

执行时机是: 对象实例化之前执行。

determineCandidateConstructors:该触发点发生在postProcessBeforeInstantiation之后,用于确定该bean的构造函数之用,返回的是该bean的所有构造函数列表。用户可以扩展这个点,来自定义选择相应的构造器来实例化这个bean。

(3)predictBeanType

预测Bean的类型,返回第一个预测成功的Class类型,如果不能预测返回null;当你调用BeanFactory.getType(name)时当通过Bean定义无法得到Bean类型信息时就调用该回调方法来决定类型信息;BeanFactory.isTypeMatch(name, targetType)用于检测给定名字的Bean是否匹配目标类型(如在依赖注入时需要使用)。

predictBeanType:该触发点发生在postProcessBeforeInstantiation之前,这个方法用于预测Bean的类型,返回第一个预测成功的Class类型,如果不能预测返回null;当你调用BeanFactory.getType(name)时当通过bean的名字无法得到bean类型信息时就调用该回调方法来决定类型信息。

1.3 使用场景

SmartInstantiationAwareBeanPostProcessor--determineCandidateConstructors处理器的应用场景:

当一个bean中有两个构造方法的时候,一个无参构造方法,一个有参构造方法,那么spring在进行bean初始化的时候回默认调用无参的构造方法:

例如:如下IndexServiceImpl中有两个构造方法

那么在spring进行实例化的过程中:

而如果我们想要执行有参的构造方法,则需要在有参构造方法上面加上@Autowired注解即可:

执行结果:发现spring执行了有参的构造方法

Spring推断构造方法的过程:在这个过程中,如果推断出有一个构造方法加了@Autowired注解,那么spring会把它放到一个临时变量当中,在判断临时变量是否为空,如果不为空,则把这个变量转换成临时数组返回出去,而如果构造方法都没有加@Autowired注解,那么spring就无法判断要把哪个加入到临时变量中,所以最后返回一个null,然后spring根据返回的null来使用默认的构造方法。






二、BeanFactoryPostProcessor扩展实现方式

方式一:使用@Configuration + @Bean 方式初始化

方式二:使用@ComponentScan + @Component方式初始化

接下来通过方式二来更深入的理解一下这个类的几个方法。

2.1 构建一个应用

这里使用了上一节构建的应用,你可以接着或者重新构建一个新的Spring Boot项目。

2.2 实现接口InstantiationAwareBeanPostProcessor

创建一个类,实现接口SmartInstantiationAwareBeanPostProcessor:

package com.kfit.config;import org.springframework.beans.BeansException;import org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor;import org.springframework.stereotype.Component;import java.lang.reflect.Constructor;/** * SmartInstantiationAwareBeanPostProcessor扩展点 * * @author 悟纤「公众号SpringBoot」 * @date 2022-06-22 * @slogan 大道至简 悟在天成 */@Componentpublic class MySmartInstantiationAwareBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor {    /**     * 预测Bean的类型,返回第一个预测成功的Class类型,如果不能预测返回null     * @param beanClass     * @param beanName     * @return     * @throws BeansException     */    @Override    public Class<?> predictBeanType(Class<?> beanClass, String beanName) throws BeansException {        System.out.println("MySmartInstantiationAwareBeanPostProcessor.predictBeanType,beanName:"+beanName);        return null;    }    /**     * 选择合适的构造器,比如目标对象有多个构造器,在这里可以进行一些定制化,选择合适的构造器     *     * @param beanClass : beanClass参数表示目标实例的类型     * @param beanName : beanName是目标实例在Spring容器中的name     * @return  : 返回值是个构造器数组,如果返回null,会执行下一个PostProcessor的determineCandidateConstructors方法;否则选取该PostProcessor选择的构造器     * @throws BeansException     */    @Override    public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) throws BeansException {        System.out.println("MySmartInstantiationAwareBeanPostProcessor.determineCandidateConstructors,beanName:"+beanName);        return null;    }    /**     *  获得提前暴露的bean引用,主要用于解决循环引用的问题     *  (只有单例对象才会调用此方法)     * @param bean     * @param beanName     * @return     * @throws BeansException     */    @Override    public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {        System.out.println("MySmartInstantiationAwareBeanPostProcessor.getEarlyBeanReference,beanName:"+beanName);        return null;    }}

2.3 启动测试

运行项目,看下效果:

三、AutowiredAnnotationBeanPostProcessor

接下来以AutowiredAnnotationBeanPostProcessor 来看看SmartInstantiationAwareBeanPostProcessor是如何被使用的。

3.1 关键代码

以下为AutowiredAnnotationBeanPostProcessor应用SmartInstantiationAwareBeanPostProcessor的关键代码:

@Override@Nullablepublic Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, final String beanName)        throws BeanCreationException {    // Let's check for lookup methods here...    if (!this.lookupMethodsChecked.contains(beanName)) {        try {            ReflectionUtils.doWithMethods(beanClass, method -> {                Lookup lookup = method.getAnnotation(Lookup.class);                if (lookup != null) {                    Assert.state(this.beanFactory != null, "No BeanFactory available");                    LookupOverride override = new LookupOverride(method, lookup.value());                    try {                        RootBeanDefinition mbd = (RootBeanDefinition)                                this.beanFactory.getMergedBeanDefinition(beanName);                        mbd.getMethodOverrides().addOverride(override);                    }                    catch (NoSuchBeanDefinitionException ex) {                        throw new BeanCreationException(beanName,                                "Cannot apply @Lookup to beans without corresponding bean definition");                    }                }            });        }        catch (IllegalStateException ex) {            throw new BeanCreationException(beanName, "Lookup method resolution failed", ex);        }        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);                Constructor<?> requiredConstructor = null;                Constructor<?> defaultConstructor = null;                //这个貌似是 Kotlin 上用的, 不用管它                Constructor<?> primaryConstructor = BeanUtils.findPrimaryConstructor(beanClass);                int nonSyntheticConstructors = 0;                //遍历这些构造函数                for (Constructor<?> candidate : rawCandidates) {                    //判断构造方法是否是合成的                    if (!candidate.isSynthetic()) {                        nonSyntheticConstructors++;                    }                    else if (primaryConstructor != null) {                        continue;                    }                    //查看是否有 @Autowired 注解                    //如果有多个构造方法, 可以通过标注 @Autowired 的方式来指定使用哪个构造方法                    AnnotationAttributes 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) {                        if (requiredConstructor != null) {                            throw new BeanCreationException(beanName,                                    "Invalid autowire-marked constructor: " + candidate +                                            ". Found constructor with 'required' Autowired annotation already: " +                                            requiredConstructor);                        }                        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;                    }                }                //到这里, 已经循环完了所有的构造方法                //候选者不为空时                if (!candidates.isEmpty()) {                    // Add default constructor to list of optional constructors, as fallback.                    if (requiredConstructor == null) {                        if (defaultConstructor != null) {                            candidates.add(defaultConstructor);                        }                        else if (candidates.size() == 1 && logger.isInfoEnabled()) {                            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 = candidates.toArray(new Constructor<?>[0]);                }                //类的构造方法只有1个, 且该构造方法有多个参数                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};                }                //这里也不会进, 因为 primaryConstructor = null                else if (nonSyntheticConstructors == 1 && primaryConstructor != null) {                    candidateConstructors = new Constructor<?>[] {primaryConstructor};                }                else {                    //如果方法进了这里, 就是没找到合适的构造方法                    //1. 类定义了多个构造方法, 且没有 @Autowired , 则有可能会进这里                    candidateConstructors = new Constructor<?>[0];                }                this.candidateConstructorsCache.put(beanClass, candidateConstructors);            }        }    }   //这里如果没找到, 则会返回 null, 而不会返回空数组    return (candidateConstructors.length > 0 ? candidateConstructors : null);}

3.2 代码说明

以上方法比较长, 但是仔细看,大致可以划分为几个步骤:

(1)获取类的所有构造方法

(2)遍历构造方法

- 只有一个无参构造方法, 则返回null。

- 只有一个有参构造方法, 则返回这个构造方法。

- 有多个构造方法且没有@Autowired, 此时spring则会蒙圈了, 不知道使用哪一个了. 这里的后置处理器, 翻译过来, 叫智能选择构造方法后置处理器。当选择不了的时候, 干脆返回 null。

- 有多个构造方法, 且在其中一个方法上标注了 @Autowired , 则会返回这个标注的构造方法

- 有多个构造方法, 且在多个方法上标注了@Autowired, 则spring会抛出异常, spring会认为, 你指定了几个给我, 是不是你弄错了。



购买完整视频,请前往:http://www.mark-to-win.com/TeacherV2.html?id=287