Spring BeanFactory 中的类型推断

Spring BeanFactory 中的类型推断

Spring 系列目录(https://www.cnblogs.com/binarylei/p/10117436.html)

Spring 容器中可以根据 beanName 查找其类型,其推断方式和 bean 的创建方式密切相关,并且 Spring 中有一个原则是尽可能的不要通过创建 bean 来获取其类型,除了 FactoryBean 只有通过创建对象调用其 getObjectType 方法,但也只是部分的创建该 FactoryBean(所谓的部分创建是指只实例化对象,而不进行属性注入和初始化过程):

  1. 对于缓存中存在单例的 bean,则直接根据对象获取其类型。
  2. 对于 FactoryBean 创建的 bean,Spring 先根据 FactoryBean 的泛型推断其创建的 bean 类型,如果没有指定则会部分实例化该 FactoryBean 后调用 getObjectType 方法。
  3. 对于工厂方法,Spring 不会实例化这个对象,而是用该方法的返回值类型来进行推断。如果该方法定义了泛型且返回值的类型恰好和泛型有关,则要通过传递的参数来进一步推断,但在 @Spring 5.1.3 似乎有 BUG。
  4. 工厂方法也有可能返回一个 FactoryBean 类型,静态工厂和实例工厂方法似乎处理的结果不一样。

一、Spring 类型推断测试

(1) 环境准备

public class User {
}

// 如果 FactoryBean 没有指定 User 类型则要部分实例化对象
public class UserFactoryBean implements FactoryBean<User> {
    @Override
    public User getObject() throws Exception {
        return new User();
    }

    @Override
    public Class<?> getObjectType() {
        return User.class;
    }
}

public class UserFactory {
    // 1. 实例工厂
    public User getObject1() {
        return new User();
    }

    // 2. 静态工厂
    public static User getObject2() {
        return new User();
    }

    // 3.1 带参的工厂方法
    public User getObject3(String username, String password) {
        return new User();
    }

    // 3.2 带泛型的工厂方法,但返回值类型和泛型无关
    public <T, K, V> User getObject4(T t, String username) {
        return new User();
    }

    // 3.3 带泛型的工厂方法,但返回值类型由参数决定
    public <T, K, V> T getObject5(T t) {
        return t;
    }

    // 4.1 静态工厂方法返回类型为 FactoryBean
    public static FactoryBean<User> getObject6() {
        return new UserFactoryBean();
    }

    // 4.2 实例工厂方法返回类型为 FactoryBean
    public FactoryBean<User> getObject7() {
        return new UserFactoryBean();
    }
}

(2) xcml 配置

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--1. 直接定义 className-->
    <bean id="bean1" class="com.github.binarylei.spring.beans.factory.test.BeanFactoryTypeInferenceTest.User"/>

    <!--2. FactoryBean-->
    <bean id="bean2" class="com.github.binarylei.spring.beans.factory.test.BeanFactoryTypeInferenceTest.UserFactoryBean"/>

    <!--3. 实例工厂-->
    <bean id="userFactory" class="com.github.binarylei.spring.beans.factory.test.BeanFactoryTypeInferenceTest.UserFactory"/>
    <bean id="bean3" factory-bean="userFactory" factory-method="getObject1"/>

    <!--4. 静态工厂-->
    <bean id="bean4" class="com.github.binarylei.spring.beans.factory.test.BeanFactoryTypeInferenceTest.UserFactory" factory-method="getObject2"/>

    <!--5. 带参的工厂方法,和构造器注入类似-->
    <!--5.1 工厂方法没有定义泛型-->
    <bean id="bean5.1" factory-bean="userFactory" factory-method="getObject3">
        <constructor-arg index="0" value="0"/>
        <constructor-arg index="1" value="1"/>
    </bean>

    <!--5.2 工厂方法定义泛型,但返回值类型与泛型无关-->
    <bean id="bean5.2" factory-bean="userFactory" factory-method="getObject4">
        <constructor-arg index="0" value="0"/>
        <constructor-arg index="1" value="1"/>
    </bean>

    <!--5.3 工厂方法定义泛型,返回值类型与参数类型决定-->
    <bean id="bean5.3" factory-bean="userFactory" factory-method="getObject5">
        <constructor-arg index="0" value="0"/>
    </bean>

    <!--6 静态工厂方法的返回值为一个 FactoryBean 类型-->
    <bean id="bean6.1" class="com.github.binarylei.spring.beans.factory.test.BeanFactoryTypeInferenceTest.UserFactory" factory-method="getObject6"/>

    <!--7 实例工厂方法的返回值为一个 FactoryBean 类型-->
    <bean id="bean6.2" factory-bean="userFactory" factory-method="getObject7"/>
</beans>

(3) 测试一把

@Test
public void test() {
    DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
    XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(lbf);
    reader.loadBeanDefinitions(new ClassPathResource("spring-context-factory.xml"));

     // 1. 直接定义 className
    Assert.assertTrue(lbf.isTypeMatch("bean1", User.class));
    // 2. FactoryBean
    Assert.assertTrue(lbf.isTypeMatch("bean2", User.class));
    // 3. 实例工厂
    Assert.assertTrue(lbf.isTypeMatch("bean3", User.class));
    // 4. 静态工厂
    Assert.assertTrue(lbf.isTypeMatch("bean4", User.class));
    // 5.1 工厂方法没有定义泛型
    Assert.assertTrue(lbf.isTypeMatch("bean5.1", User.class));
    // 5.2 工厂方法定义泛型,但返回值类型与泛型无关
    Assert.assertTrue(lbf.isTypeMatch("bean5.2", User.class));
    // 5.3 工厂方法定义泛型,返回值类型与参数类型决定,无法获取 @Spring 5.1.3
    Assert.assertFalse(lbf.isTypeMatch("bean5.3", User.class));
    // 6.1 静态工厂方法返回类型为 FactoryBean
    Assert.assertTrue(lbf.isTypeMatch("bean6.1", User.class));
    // 6.2 实例工厂方法返回类型为 FactoryBean
    Assert.assertFalse(lbf.isTypeMatch("bean6.2", User.class));
}

可以看到工厂方法带有泛型且返回值类型和泛型有关后 Spring 不能正确处理了,别处实例的工厂方法返回 FactoryBean 也不能正确处理。

二、Spring 类型推断源码分析

2.1 类型匹配的入口 - isTypeMatch

@Override
public boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException {
    return isTypeMatch(name, ResolvableType.forRawClass(typeToMatch));
}

@Override
public boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException {
    String beanName = transformedBeanName(name);

    // 1. 根据实例化后的对象获取 bean 的类型,注意 FactoryBean 的处理即可
    Object beanInstance = getSingleton(beanName, false);
    if (beanInstance != null && beanInstance.getClass() != NullBean.class) {
        // 1.1 如果是 FactoryBean 类型,此时需要判断是否要查找的就是这个工厂对象,判断 beanName 是否是以 & 开头
        //     如果是其创建的类型,则需要调用 getTypeForFactoryBean 从这个 FactoryBean 实例中获取真实类型
        if (beanInstance instanceof FactoryBean) {
            if (!BeanFactoryUtils.isFactoryDereference(name)) {
                Class<?> type = getTypeForFactoryBean((FactoryBean<?>) beanInstance);
                return (type != null && typeToMatch.isAssignableFrom(type));
            } else {
                return typeToMatch.isInstance(beanInstance);
            }
        // 1.2 如果是普通 bean 则可直接判断类型,当然 Spring 还考虑的泛型的情况
        } else if (!BeanFactoryUtils.isFactoryDereference(name)) {
            if (typeToMatch.isInstance(beanInstance)) {
                return true;
            } else if (typeToMatch.hasGenerics() && containsBeanDefinition(beanName)) {
                // AOP 有关 ????
                RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
                Class<?> targetType = mbd.getTargetType();
                if (targetType != null && targetType != ClassUtils.getUserClass(beanInstance) &&
                        typeToMatch.isAssignableFrom(targetType)) {
                    Class<?> classToMatch = typeToMatch.resolve();
                    return (classToMatch == null || classToMatch.isInstance(beanInstance));
                }
            }
        }
        return false;
    } else if (containsSingleton(beanName) && !containsBeanDefinition(beanName)) {
        // null instance registered
        return false;
    }

    // 2. 父工厂,没什么好说的
    BeanFactory parentBeanFactory = getParentBeanFactory();
    if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
        return parentBeanFactory.isTypeMatch(originalBeanName(name), typeToMatch);
    }

    // 3. 下面就要从 bean 的定义中获取该 bean 的类型了
    RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);

    Class<?> classToMatch = typeToMatch.resolve();
    if (classToMatch == null) {
        classToMatch = FactoryBean.class;
    }
    Class<?>[] typesToMatch = (FactoryBean.class == classToMatch ?
            new Class<?>[] {classToMatch} : new Class<?>[] {FactoryBean.class, classToMatch});

    // 3.1 AOP 代理时会将原始的 BeanDefinition 存放到 decoratedDefinition 属性中,可以行忽略这部分
    BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
    if (dbd != null && !BeanFactoryUtils.isFactoryDereference(name)) {
        RootBeanDefinition tbd = getMergedBeanDefinition(dbd.getBeanName(), dbd.getBeanDefinition(), mbd);
        Class<?> targetClass = predictBeanType(dbd.getBeanName(), tbd, typesToMatch);
        if (targetClass != null && !FactoryBean.class.isAssignableFrom(targetClass)) {
            return typeToMatch.isAssignableFrom(targetClass);
        }
    }

    // 3.2 predictBeanType 推断 beanName 的类型,主要的逻辑
    Class<?> beanType = predictBeanType(beanName, mbd, typesToMatch);
    if (beanType == null) {
        return false;
    }

    // 3.3 处理 FactoryBean 类型
    if (FactoryBean.class.isAssignableFrom(beanType)) {
        if (!BeanFactoryUtils.isFactoryDereference(name) && beanInstance == null) {
            // 此时需要从 FactoryBean 中推断出真实类型
            beanType = getTypeForFactoryBean(beanName, mbd);
            if (beanType == null) {
                return false;
            }
        }
    // 3.4 beanType 不是 FactoryBean 类型,但是又要获取 FactoryBean 的类型???
    } else if (BeanFactoryUtils.isFactoryDereference(name)) {
        // Special case: A SmartInstantiationAwareBeanPostProcessor returned a non-FactoryBean
        // type but we nevertheless are being asked to dereference a FactoryBean...
        // Let's check the original bean class and proceed with it if it is a FactoryBean.
        beanType = predictBeanType(beanName, mbd, FactoryBean.class);
        if (beanType == null || !FactoryBean.class.isAssignableFrom(beanType)) {
            return false;
        }
    }

    // 3.5 优先从缓存中判断,可以比较泛型
    ResolvableType resolvableType = mbd.targetType;
    if (resolvableType == null) {
        resolvableType = mbd.factoryMethodReturnType;
    }
    if (resolvableType != null && resolvableType.resolve() == beanType) {
        return typeToMatch.isAssignableFrom(resolvableType);
    }
    return typeToMatch.isAssignableFrom(beanType);
}

上面的代码一大堆,逻辑也比较复杂,我们现在只需要明白三点:

  1. Spring 先直接从缓存中获取这个 bean 实例,再根据对象推断其类型。如果 bean 还没有创建或者干脆就不是单例,则只能根据定义这个 bean 的 BeanDefinition 获取了。
  2. 根据 BeanDefinition 获取其类型,Spring 全部委托给了 predictBeanType(beanName, mbd, typesToMatch) 方法。
  3. 如果是 FactoryBean,要获取其真实类型则通过 getTypeForFactoryBean 方法,这个方法有两个重载的方法,即可以直接通过实例对象获取,也可以通过定义的 BeanDefinition 获取对象类型。

下面我们就分别介绍一下这两个方法。

2.2 根据 FactoryBean 获取真实类型 - getTypeForFactoryBean

getTypeForFactoryBean 相对来说比较简单,我们先说这个方法。AbstractBeanFactory#getTypeForFactoryBean 实现了这个方法,其子类又重载了这个方法 AbstractAutowireCapableBeanFactory#getTypeForFactoryBean

(1) AbstractBeanFactory#getTypeForFactoryBean

protected Class<?> getTypeForFactoryBean(String beanName, RootBeanDefinition mbd) {
    if (!mbd.isSingleton()) {
        return null;
    }
    FactoryBean<?> factoryBean = doGetBean(FACTORY_BEAN_PREFIX + beanName, FactoryBean.class, null, true);
    return getTypeForFactoryBean(factoryBean);
}

protected Class<?> getTypeForFactoryBean(final FactoryBean<?> factoryBean) {
    return factoryBean.getObjectType(); 
}

怎么样是不是很简单,先创建这个 FactoryBean 的实例,然后调用其 getObjectType 方法获取真实类型。

(2) AbstractAutowireCapableBeanFactory#getTypeForFactoryBean

@Override
protected Class<?> getTypeForFactoryBean(String beanName, RootBeanDefinition mbd) {
    if (mbd.getInstanceSupplier() != null) {
        ResolvableType targetType = mbd.targetType;
        if (targetType != null) {
            Class<?> result = targetType.as(FactoryBean.class).getGeneric().resolve();
            if (result != null) {
                return result;
            }
        }
        if (mbd.hasBeanClass()) {
            Class<?> result = GenericTypeResolver.resolveTypeArgument(mbd.getBeanClass(), FactoryBean.class);
            if (result != null) {
                return result;
            }
        }
    }

    String factoryBeanName = mbd.getFactoryBeanName();
    String factoryMethodName = mbd.getFactoryMethodName();

    if (factoryBeanName != null) {
        if (factoryMethodName != null) {
            // Try to obtain the FactoryBean's object type from its factory method declaration
            // without instantiating the containing bean at all.
            BeanDefinition fbDef = getBeanDefinition(factoryBeanName);
            if (fbDef instanceof AbstractBeanDefinition) {
                AbstractBeanDefinition afbDef = (AbstractBeanDefinition) fbDef;
                if (afbDef.hasBeanClass()) {
                    Class<?> result = getTypeForFactoryBeanFromMethod(afbDef.getBeanClass(), factoryMethodName);
                    if (result != null) {
                        return result;
                    }
                }
            }
        }
        // If not resolvable above and the referenced factory bean doesn't exist yet,
        // exit here - we don't want to force the creation of another bean just to
        // obtain a FactoryBean's object type...
        if (!isBeanEligibleForMetadataCaching(factoryBeanName)) {
            return null;
        }
    }

    // Let's obtain a shortcut instance for an early getObjectType() call...
    FactoryBean<?> fb = (mbd.isSingleton() ?
            getSingletonFactoryBeanForTypeCheck(beanName, mbd) :
            getNonSingletonFactoryBeanForTypeCheck(beanName, mbd));

    if (fb != null) {
        // Try to obtain the FactoryBean's object type from this early stage of the instance.
        Class<?> result = getTypeForFactoryBean(fb);
        if (result != null) {
            return result;
        }
        else {
            // No type found for shortcut FactoryBean instance:
            // fall back to full creation of the FactoryBean instance.
            return super.getTypeForFactoryBean(beanName, mbd);
        }
    }

    if (factoryBeanName == null && mbd.hasBeanClass()) {
        // No early bean instantiation possible: determine FactoryBean's type from
        // static factory method signature or from class inheritance hierarchy...
        if (factoryMethodName != null) {
            return getTypeForFactoryBeanFromMethod(mbd.getBeanClass(), factoryMethodName);
        }
        else {
            return GenericTypeResolver.resolveTypeArgument(mbd.getBeanClass(), FactoryBean.class);
        }
    }

    return null;
}

2.3 从 BeanDefinition 推断类型 - predictBeanType

我们先从简单的看起,AbstractBeanFactory#predictBeanType 实现了这个方法,其子类又重载了这个方法 AbstractAutowireCapableBeanFactory#predictBeanType。

(1) AbstractBeanFactory#predictBeanType

protected Class<?> predictBeanType(String beanName, RootBeanDefinition mbd, Class<?>... typesToMatch) {
    // 1. 直接从缓存中获取
    Class<?> targetType = mbd.getTargetType();
    if (targetType != null) {
        return targetType;
    }
    // 2. 工厂方法一律返回 null,子类会重载后解析对应的 getFactoryMethodName
    if (mbd.getFactoryMethodName() != null) {
        return null;
    }
    // 3. 解析 BeanDefinition 的 className,如果已经加载则直接从缓存中获取
    return resolveBeanClass(mbd, beanName, typesToMatch);
}

可以看到最终是从 BeanDefinition 中解析配置的 className 属性,将其加载到 JVM 中。它有三个参数,毫无疑问的是 mbd 是必须的,beanName 记录异常时使用,那 typesToMatch 是干嘛的呢?带着这个疑问我们看一下源码。

protected Class<?> resolveBeanClass(final RootBeanDefinition mbd, String beanName, 
        final Class<?>... typesToMatch) throws CannotLoadBeanClassException {
    if (mbd.hasBeanClass()) {
        return mbd.getBeanClass();
    }
    return doResolveBeanClass(mbd, typesToMatch);       
}
private Class<?> doResolveBeanClass(RootBeanDefinition mbd, Class<?>... typesToMatch)
        throws ClassNotFoundException {

    ClassLoader beanClassLoader = getBeanClassLoader();
    ClassLoader classLoaderToUse = beanClassLoader;
    // 1. Spring 自定义的类型器 DecoratingClassLoader 修改了 JDK 的类加载规则,自己先加载一把,没有再特派给父加载器
    //    这就产生了一个问题,每个临时的类加载器可能加载同一个类可能出现多个
    //    所以可以将其加入到 excludeClass 仍采用双亲委派
    if (!ObjectUtils.isEmpty(typesToMatch)) {
        ClassLoader tempClassLoader = getTempClassLoader();
        if (tempClassLoader != null) {
            classLoaderToUse = tempClassLoader;
            if (tempClassLoader instanceof DecoratingClassLoader) {
                DecoratingClassLoader dcl = (DecoratingClassLoader) tempClassLoader;
                for (Class<?> typeToMatch : typesToMatch) {
                    dcl.excludeClass(typeToMatch.getName());
                }
            }
        }
    }
    // 2. 如果 className 含有点位符,解析后发生了变化,则不用缓存,以后每次都解析一次
    String className = mbd.getBeanClassName();
    if (className != null) {
        Object evaluated = evaluateBeanDefinitionString(className, mbd);
        if (!className.equals(evaluated)) {
            if (evaluated instanceof Class) {
                return (Class<?>) evaluated;
            } else if (evaluated instanceof String) {
                return ClassUtils.forName((String) evaluated, classLoaderToUse);
            } else {
                throw new IllegalStateException("Invalid class name expression result: " + evaluated);
            }
        }
        if (classLoaderToUse != beanClassLoader) {
            return ClassUtils.forName(className, classLoaderToUse);
        }
    }
    // 3. 解析 className 后缓存起来
    return mbd.resolveBeanClass(beanClassLoader);
}

至此,根据 BeanDefinition 解析 bean 的类型就完成了,最终还是回到了我们在 xml 文件中配置的 class 上来了,只是 Spring 的解析考虑了很多情况,一下子就复杂起来了。 想必现在对 typesToMatch 也有一定的了解了,就是为了保证要匹配的类型是同一个类加载器加载的,这里也就是 JDK 的系统类加载器 - AppClassLoader,这样调用 typeToMatch.isAssignableFrom(type) 方法才有意义。

(2) AbstractAutowireCapableBeanFactory#predictBeanType

AbstractAutowireCapableBeanFactory 又对 predictBeanType 进行了重载,增加了对工厂方法 factoryMethodName 的解析。

@Override
protected Class<?> predictBeanType(String beanName, RootBeanDefinition mbd, Class<?>... typesToMatch) {
    // 1. 增加了对工厂 factoryMethod 的解析
    Class<?> targetType = determineTargetType(beanName, mbd, typesToMatch);

    // 2. 后置处理器 SmartInstantiationAwareBeanPostProcessors 
    if (targetType != null && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
                SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
                Class<?> predicted = ibp.predictBeanType(targetType, beanName);
                if (predicted != null && (typesToMatch.length != 1 || FactoryBean.class != typesToMatch[0] ||
                        FactoryBean.class.isAssignableFrom(predicted))) {
                    return predicted;
                }
            }
        }
    }
    return targetType;
}

// 怎么样,逻辑还是之前的一样,只是增加对 factoryMethodName 的处理
protected Class<?> determineTargetType(String beanName, RootBeanDefinition mbd, Class<?>... typesToMatch) {
    Class<?> targetType = mbd.getTargetType();
    if (targetType == null) {
        targetType = (mbd.getFactoryMethodName() != null ?
                getTypeForFactoryMethod(beanName, mbd, typesToMatch) :
                resolveBeanClass(mbd, beanName, typesToMatch));
        if (ObjectUtils.isEmpty(typesToMatch) || getTempClassLoader() == null) {
            mbd.resolvedTargetType = targetType;
        }
    }
    return targetType;
}

在这里,我们重点关注 getTypeForFactoryMethod 方法,Spring 是如何从一个工厂方法中获取其类型的。

protected Class<?> getTypeForFactoryMethod(String beanName, RootBeanDefinition mbd, Class<?>... typesToMatch) {
    // 1. 缓存中直接取
    ResolvableType cachedReturnType = mbd.factoryMethodReturnType;
    if (cachedReturnType != null) {
        return cachedReturnType.resolve();
    }

    Class<?> factoryClass;
    boolean isStatic = true;

    // 2. 在 Spring 中有静态工厂和实例工厂之分,如果是实例工厂名称不能是当前的 beanName
    String factoryBeanName = mbd.getFactoryBeanName();
    if (factoryBeanName != null) {
        if (factoryBeanName.equals(beanName)) {
            throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
                    "factory-bean reference points back to the same bean definition");
        }
        // 2.1 获取实例工厂的类型
        factoryClass = getType(factoryBeanName);
        isStatic = false;
    } else {
        // 2.2 静态工厂只能是静态方法,解析自己的 BeanDefinition 就可以了
        factoryClass = resolveBeanClass(mbd, beanName, typesToMatch);
    }

    if (factoryClass == null) {
        return null;
    }
    // 2.3 如果是 CGLIB 代理,获取其真实类型
    factoryClass = ClassUtils.getUserClass(factoryClass);

    // 3.1 如果有多个方法同名,则取其返回傎的公有类型,除非为 null
    Class<?> commonType = null;
    // 3.2 缓存这个工厂方法
    Method uniqueCandidate = null;
    // 3.3 如果方法含有泛型,则需要根据传递的参数进一步判断返回值类型
    int minNrOfArgs =
            (mbd.hasConstructorArgumentValues() ? mbd.getConstructorArgumentValues().getArgumentCount() : 0);
    Method[] candidates = this.factoryMethodCandidateCache.computeIfAbsent(
            factoryClass, ReflectionUtils::getUniqueDeclaredMethods);

    // 4. 遍历所有的名称为工厂方法的
    for (Method candidate : candidates) {
        if (Modifier.isStatic(candidate.getModifiers()) == isStatic && mbd.isFactoryMethod(candidate) &&
                candidate.getParameterCount() >= minNrOfArgs) {
            // 4.1 方法中定义了泛型,则需要将配置的构造参数进行比较了,但似乎有问题
            // 4.1.1 getTypeParameters 获取定义的泛型个数
            if (candidate.getTypeParameters().length > 0) {
                // 4.1.2 getParameterTypes 获取该方法的参数列表
                Class<?>[] paramTypes = candidate.getParameterTypes();
                String[] paramNames = null;
                ParameterNameDiscoverer pnd = getParameterNameDiscoverer();
                if (pnd != null) {
                    paramNames = pnd.getParameterNames(candidate);
                }
                ConstructorArgumentValues cav = mbd.getConstructorArgumentValues();
                Set<ConstructorArgumentValues.ValueHolder> usedValueHolders = new HashSet<>(paramTypes.length);
                Object[] args = new Object[paramTypes.length];
                // 4.1.3 根据类型和参数名匹配真实的参数
                for (int i = 0; i < args.length; i++) {
                    ConstructorArgumentValues.ValueHolder valueHolder = cav.getArgumentValue(
                            i, paramTypes[i], (paramNames != null ? paramNames[i] : null), usedValueHolders);
                    if (valueHolder == null) {
                        valueHolder = cav.getGenericArgumentValue(null, null, usedValueHolders);
                    }
                    if (valueHolder != null) {
                        args[i] = valueHolder.getValue();
                        usedValueHolders.add(valueHolder);
                    }
                }
                // 4.1.4 解析返回值对应的泛型类型
                Class<?> returnType = AutowireUtils.resolveReturnTypeForFactoryMethod(
                        candidate, args, getBeanClassLoader());
                uniqueCandidate = (commonType == null && returnType == candidate.getReturnType() ?
                        candidate : null);
                commonType = ClassUtils.determineCommonAncestor(returnType, commonType);
                if (commonType == null) {
                    return null;
                }
            // 4.2 直接获取方法的返回值类型,如果有多个同名方法取其公共的祖先即可,没有就直接返回 null
            } else {
                // 第一次匹配上会缓存这个方法,但再次匹配上了,不好意思有重名的方法,直接清空
                uniqueCandidate = (commonType == null ? candidate : null);
                commonType = ClassUtils.determineCommonAncestor(candidate.getReturnType(), commonType);
                if (commonType == null) {
                    return null;
                }
            }
        }
    }

    // 5.1 如果同名的方法只有一个,那么将这个工厂方法直接缓存起来
    mbd.factoryMethodToIntrospect = uniqueCandidate;
    if (commonType == null) {
        return null;
    }
    // 5.2 如果只有唯一的工厂方法,那么尽可能缓存完型的类型,包括泛型。所以再解析一次用于缓存
    cachedReturnType = (uniqueCandidate != null ?
            ResolvableType.forMethodReturnType(uniqueCandidate) : ResolvableType.forClass(commonType));
    mbd.factoryMethodReturnType = cachedReturnType;
    return cachedReturnType.resolve();
}

根据工厂方法推断 bean 的类型看起来很复杂,但逻辑还是很清晰的:

  1. 直接从缓存中获取这个工厂方法的返回值类型。
  2. 解析工厂方法的类型,这里分为静态工厂和实例工厂,静态工厂即为自己本身,实例工厂为配置的 factory-bean
  3. 遍历这个工厂类的每个和 factory-method 同名的工厂方法,包括其父类。Spring 增加了对泛型返回值方法的支持,但我在测试的时候失败了,不知道是不是使用不对。总之,就是遍历这些方法的返回值类型,如果有多个就取其公共的类型。
  4. 如果只有唯一的一个工厂方法,缓存起来,同时缓存解析后的类型,尽可能保存完整的类型,包括泛型。

对于泛型返回值类型再多说一句,Class<?> returnType = AutowireUtils.resolveReturnTypeForFactoryMethod( candidate, args, getBeanClassLoader()); 在测试时确实没有问题,后来发现是 Spring 在解析 xml 文件时对构造参数做了一个封装,也就是 valueHolder.getValue() 不是配置的类型,而是 TypedStringValue 类型,导致解析出现问题。

参考:

1 . 《》:<>


每天用心记录一点点。内容也许不重要,但习惯很重要!

猜你喜欢

转载自www.cnblogs.com/binarylei/p/10332100.html
今日推荐