spring之getBeanByType探究

前言

spring容器获取bean的方式主要有两种,即byNamebyType

byName方式相对简单,即Object getBean(String name),通过beanName获取,因为容器中存储的就是一个beanName->bean实体的映射,如果没有创建,则通过beanName查找bean定义,通过bean定义去创建即可

而byType,即T getBean(Class requiredType),则复杂一点,因为不管是bean定义容器还是bean容器存储形式都是以beanName为key的map,所以它的获取方式肯定要多一步type->name的转换

源码

其实虽然容器的key是beanName,但想一下getByType并不难实现,只要循环bean定义看看哪些bean的class是所查找的type,获取到对应的beanName,调用getByName就解决了

其实源码也正是如此,跟一下源码(以下代码省略了一些支线逻辑)

getBeanByType
public  T getBean(Class requiredType) throws BeansException {
    return getBean(requiredType, (Object[]) null);
}
public  T getBean(Class requiredType, @Nullable Object... args) throws BeansException {
             // 调用resolveBean
    Object resolved = resolveBean(ResolvableType.forRawClass(requiredType), args, false);
    return (T) resolved;
}

最终调用resolveBean方法

resolveBean
private  T resolveBean(ResolvableType requiredType, @Nullable Object[] args, boolean nonUniqueAsNull) {
    NamedBeanHolder namedBean = resolveNamedBean(requiredType, args, nonUniqueAsNull);
    if (namedBean != null) {
        return namedBean.getBeanInstance();
    }
    // 省略
    return null;
}

调用resolveNamedBean

resolveNamedBean
private  NamedBeanHolder resolveNamedBean(
            ResolvableType requiredType, @Nullable Object[] args, boolean nonUniqueAsNull) throws BeansException {
    // 调用getBeanNamesForType查找候选beanNames
    String[] candidateNames = getBeanNamesForType(requiredType);
    // 只有一个候选者,直接返回这个beanName
    if (candidateNames.length == 1) {
        String beanName = candidateNames[0];
        // 这里的getBean就是getBeanByName
        return new NamedBeanHolder<>(beanName, (T) getBean(beanName, requiredType.toClass(), args));
    }
    else if (candidateNames.length > 1) {
        // 省略,大体意思是多个后选择从中选一个
    }
    return null;
}

所以重点就来到了getBeanNamesForType,字面意思传给它一个type能返回所有该type的beanName,获取到这些beanName如果只有一个就达成目标返回,多个就按自己的规矩选一个,最终通过getBeanByName实际获取bean

getBeanNamesForType

getBeanNamesForType最终会走向doGetBeanNamesForType,这是spring源码的一罐命名方式,不贴代码了,直接看doGetBeanNamesForType

doGetBeanNamesForType
private String[] doGetBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
    // 准备好匹配的集合
    List result = new ArrayList<>();
    // 循环所有bean定义名集合
    for (String beanName : this.beanDefinitionNames) {
        // 省略一些别名判断,bean定义完整判断,异常处理...
        // 通过名字获取beand定义
        RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
        // 判断是不是FactoryBean         
        boolean isFactoryBean = isFactoryBean(beanName, mbd);
        BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
        // 是否匹配标识
        boolean matchFound = false;
        // 是否允许FactoryBean初始化
        boolean allowFactoryBeanInit = (allowEagerInit || containsSingleton(beanName));
        boolean isNonLazyDecorated = (dbd != null && !mbd.isLazyInit());
        // 如果不是FactoryBean
        if (!isFactoryBean) {
            if (includeNonSingletons || isSingleton(beanName, mbd, dbd)) {
                // 使用isTypeMatch判断bean是否匹配type
                matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);
            }
        }
        // 如果是FactoryBean
        else  {
            // 省略FactoryBean特殊处理
        }
        // 如果匹配,加入到匹配集合中
        if (matchFound) {
            result.add(beanName);
        }
    }
    // 省略查找手动注册单例逻辑...
    // 返回匹配集合结果
    return StringUtils.toStringArray(result);
}

先不管FactoryBean的特殊处理,看看普通的bean,最终是通过isTypeMatch方法判断是否匹配

protected boolean isTypeMatch(String name, ResolvableType typeToMatch, boolean allowFactoryBeanInit)
            throws NoSuchBeanDefinitionException {

    String beanName = transformedBeanName(name);
    boolean isFactoryDereference = BeanFactoryUtils.isFactoryDereference(name);

    // 省略判断手动注册bean是否匹配逻辑...

    // 根据beanName获取bean定义
    RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
    BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();

    // 要匹配的class
    Class classToMatch = typeToMatch.resolve();

    // 省略FactoryBean相关逻辑
    
    // bean的type
    ResolvableType beanType = null;
    
    if (beanType == null) {
        // 获取bean定义的targetType
        ResolvableType definedType = mbd.targetType;
        beanType = definedType;
    }

    // 判断beanType是否可以转换为要匹配的type
    if (beanType != null) {
        return typeToMatch.isAssignableFrom(beanType);
    }
}

实际上就是查找bean定义的targetType属性,看是否是所需type/子类/实现,如果是就匹配上了

整个过程梳理下来:
getByType就是循环bean定义,查找bean定义的targetType属性等于该type的对应beanName,再调用getByName,就完成了通过类型查找bean

getByType

FactoryBean的特殊性

上面的代码为了清晰省略了很多分支逻辑,其中FactoryBean的判断是比较重要的一环,所以还不能忽略

FactoryBean的特殊性在于,他实际是两个对象,一个工厂对象(FactoryType),一个生产的对象(ObjectType,也是一般情况我们实际需要的对象),不熟悉FactoryBean可以看这里Spring FactoryBean源码解析

问题的症结在于FactoryBean的bean定义的targetType属性是FactoryType,而我们一般需要注入的是FactoryBean.getObject生产的ObjectType

比如现在有个BookFactoryBean生产的是Book实体bean,当我们getByType(Book.class)时,bean定义中并不存在targetType==Book.class的bean定义,只有targetType==BookFactoryBean.class的bean定义,按照上面的逻辑是无法根据type获取到Book的beanName的

FactoryBean

所以再回到doGetBeanNamesForType方法找回省略的FactoryBean逻辑,看spring如何解决这个问题

doGetBeanNamesForType
private String[] doGetBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
    // 准备好匹配的集合
    List result = new ArrayList<>();
    // 循环所有bean定义名集合
    for (String beanName : this.beanDefinitionNames) {
        // 省略一些别名判断,bean定义完整判断,异常处理...
        // 通过名字获取beand定义
        RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
        // 判断是不是FactoryBean         
        boolean isFactoryBean = isFactoryBean(beanName, mbd);
        BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
        // 是否匹配标识
        boolean matchFound = false;
        // 是否允许FactoryBean初始化
        boolean allowFactoryBeanInit = (allowEagerInit || containsSingleton(beanName));
        boolean isNonLazyDecorated = (dbd != null && !mbd.isLazyInit());
        // 如果不是FactoryBean
        if (!isFactoryBean) {
            if (includeNonSingletons || isSingleton(beanName, mbd, dbd)) {
                // 使用isTypeMatch判断bean是否匹配type
                matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);
            }
        }
        // 如果是FactoryBean
        else  {
            if (includeNonSingletons || isNonLazyDecorated ||
                    (allowFactoryBeanInit && isSingleton(beanName, mbd, dbd))) {
                // 使用isTypeMatch判断FactoryBean生产的bean是否匹配type
                matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);
            }
            // 如果查不到
            if (!matchFound) {
                // 判断FactoryBean本身是否匹配type
                beanName = FACTORY_BEAN_PREFIX + beanName;
                matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);
            }
        }
        // 如果匹配,加入到匹配集合中
        if (matchFound) {
            result.add(beanName);
        }
    }
    // 省略查找手动注册bean逻辑...
    // 返回匹配集合结果
    return StringUtils.toStringArray(result);
}

可以看到,如果是FactoryBean,最终依然使用isTypeMatch进行判断,所以重点还是在这个方法

后面还有一句如果不匹配则beanName = FACTORY_BEAN_PREFIX + beanName,并再次isTypeMatch判断,其中FACTORY_BEAN_PREFIX = "&",熟悉FactoryBean的同学应该知道这是查找FactoryBean本身,因为某些特殊情况,可能我们想注入的就是这个FactoryBean本身而不是他生产的bean

重点依然是看isTypeMatch是怎么处理FactoryBean的匹配问题的

isTypeMatch
/**
** 根据beanName判断与typeToMatch是否匹配
*/
protected boolean isTypeMatch(String name, ResolvableType typeToMatch, boolean allowFactoryBeanInit)
            throws NoSuchBeanDefinitionException {

    String beanName = transformedBeanName(name);
    // beanName是不是FactoryBean本身的name,即以&开头
    boolean isFactoryDereference = BeanFactoryUtils.isFactoryDereference(name);

    // 省略判断手动注册bean是否匹配逻辑...

    // 根据beanName获取bean定义
    RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
    BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();

    // 要匹配的class
    Class classToMatch = typeToMatch.resolve();

    // 将要匹配的class和FactoryBean.class组成一个数组,因为匹配的可能有两种,一种是targetType就是class,一种是targetType是FactoryBean(保留可能性)
    if (classToMatch == null) {
        classToMatch = FactoryBean.class;
    }
    Class[] typesToMatch = (FactoryBean.class == classToMatch ?
            new Class[] {classToMatch} : new Class[] {FactoryBean.class, classToMatch});


    // 尝试预测bean的Type
    Class predictedType = null;

    // 省略修饰bean定义逻辑

    // predictBeanType(beanName, mbd, typesToMatch)就是获取bean定义的targetType
    if (predictedType == null) {
        predictedType = predictBeanType(beanName, mbd, typesToMatch);
        if (predictedType == null) {
            return false;
        }
    }

    // 尝试获取bean的实际Type
    ResolvableType beanType = null;

    // 如果是FactoryBean, 要查看它创建了什么类型的bean,而不是工厂本身的Type
    if (FactoryBean.class.isAssignableFrom(predictedType)) {
        if (beanInstance == null && !isFactoryDereference) {
            // 获取FactoryBean创建的type
            beanType = getTypeForFactoryBean(beanName, mbd, allowFactoryBeanInit);
            predictedType = beanType.resolve();
            if (predictedType == null) {
                return false;
            }
        }
    }
    else if (isFactoryDereference) {
        // 如果是FactoryBean本身,还是直接查bean定义的targetType
        predictedType = predictBeanType(beanName, mbd, FactoryBean.class);
        if (predictedType == null || !FactoryBean.class.isAssignableFrom(predictedType)) {
            return false;
        }
    }

    // 如果没有明确的beanType,但mdb的targetType或factoryMethodReturnType等于predictedType,则可以使用它们作为明确的beanType
    if (beanType == null) {
        ResolvableType definedType = mbd.targetType;
        if (definedType == null) {
            definedType = mbd.factoryMethodReturnType;
        }
        if (definedType != null && definedType.resolve() == predictedType) {
            beanType = definedType;
        }
    }

    // 如果有明确beanType,直接判断是否可转换为typeToMatch
    if (beanType != null) {
        return typeToMatch.isAssignableFrom(beanType);
    }

    // 如果没有有明确beanType,判断predictedType是否可转换为typeToMatch
    return typeToMatch.isAssignableFrom(predictedType);
}

逻辑看起来挺复杂,其实最重要的是如果是FactoryBean,调用getTypeForFactoryBean获取其创建的ObjectType,那么看看getTypeForFactoryBean是如何获取FactoryBean所创建的ObjectType

getTypeForFactoryBean
protected ResolvableType getTypeForFactoryBean(String beanName, RootBeanDefinition mbd, boolean allowInit) {
    // bean定义指明的ObjectType
    ResolvableType result = getTypeForFactoryBeanFromAttributes(mbd);
    // 取到就返回
    if (result != ResolvableType.NONE) {
        return result;
    }

    // 上面没取到,则通过doGetBean(FACTORY_BEAN_PREFIX + beanName)获取或创建FactoryBean工厂本身的对象
    if (allowInit && mbd.isSingleton()) {
        try {
            FactoryBean factoryBean = doGetBean(FACTORY_BEAN_PREFIX + beanName, FactoryBean.class, null, true);
            // 通过getTypeForFactoryBean方法获取ObjectType
            Class objectType = getTypeForFactoryBean(factoryBean);
            return (objectType != null) ? ResolvableType.forClass(objectType) : ResolvableType.NONE;
        }
        catch (BeanCreationException ex) {
            // 省略异常处理
        }
    }
    return ResolvableType.NONE;
}

上面的代码分两步,如果bean定义包含了返回的objectType,则直接返回,否则去bean容器查找FactoryBean的实例,通过getTypeForFactoryBean获取FactoryBean的ObjectType,这里getTypeForFactoryBean实际上就是调用FactoryBean.getObjectType方法

protected Class getTypeForFactoryBean(FactoryBean factoryBean) {
    try {
        return factoryBean.getObjectType();
    }
    catch (Throwable ex) {
    }
}

getObjectType就是我们实现FactoryBean接口时需要实现的方法,例如如下

@Component
public class BookFactory implements FactoryBean {
    @Override
    public Book getObject() {
        return new Book();
    }

    @Override
    public Class getObjectType() {
        return Book.class;
    }
}

总结

getBeanByType 就是循环bean定义查找targetType==type,如果是FactoryBean查找objectType==type的唯一beanName,再通过getBeanByName就获取到了bean~

你可能感兴趣的:(spring之getBeanByType探究)