Loading

Spring BeanFactory接口分析&源码解读

BeanFactory

BeanFactory位于spring-bean模块下

最基础的Bean容器接口,该接口并未定义容器应该从哪里得到Bean,只是定义了一些获取Bean的基本方法。以下是该接口提供的功能:

  1. 按名字、类型来获取Bean
  2. 允许在获取Bean时传入一些构造方法/工厂方法参数,来覆盖Bean定义时的默认参数
  3. 由于获取Bean时要检查其存在性和唯一性,BeanFactory允许这种检查在使用时按需发生
  4. Singleton和Prototype支持
  5. 可以对Bean取别名

BeanFactory应该尽可能的支持标准Bean生命周期方法,这个文档里是有的,所以我不写出来了。

StaticListableBeanFactory

下面我们将演示以下BeanFactory的基本特性,为了保持简单,我们使用它的最基础的实现类——StaticListableBeanFactory

按名字获取Bean

首先,StaticListableBeanFactory内部使用一个Map<String, Object>来保存Bean名字和Bean对象的映射,并且它提供了一个add方法来向BeanFactory中添加Bean。

创建BeanFactory,并向其中添加一个名为fruits的列表:

StaticListableBeanFactory factory = new StaticListableBeanFactory();
factory.addBean("fruits", Arrays.asList("apple", "banana", "orange"));

获取它:

List<String> fruits = (List<String>) factory.getBean("fruits");
System.out.println(fruits);

结果:

img

按类型获取Bean

List<String> fruits = factory.getBean(List.class);
System.out.println(fruits);

结果:

img

BeanProvider

前面说了,BeanFactory允许按需延时获取Bean、检查其存在性和唯一性。这是用BeanProvider来完成的。

ObjectProvider<List> provider = factory.getBeanProvider(List.class); 

上面的代码中,你并没有实际的获取Bean,如果你使用了factory.getBean(List.class),那么BeanFactory会实际的执行寻找Bean的这个操作,若Bean不存在或Bean不唯一都会直接抛出异常。BeanProvider允许将这个过程延后,在你需要时再实际获取Bean。

下面有两个List类型的Bean,但由于获取Provider的过程并没有实际寻找Bean,所以不会出现任何异常:

factory.addBean("fruits1", Arrays.asList("apple", "banana", "orange"));
factory.addBean("fruits2", Arrays.asList("peach", "mihotel"));

ObjectProvider<List> provider = factory.getBeanProvider(List.class);

调用provider.getObject,执行实际寻找Bean,这下才会抛出异常。

List list = provider.getObject();

img

我们也有一些其它方法可以用:

// getIfUnique
List list = provider.getIfUnique();
Assert.isNull(list);

// 函数式用法
provider.ifUnique(System.out::println);

// 对具有指定类型的多个Bean进行迭代
provider.iterator().forEachRemaining(System.out::println);

> StaticListableBeanFactory目前不支持ProtoType,不支持别名,不支持对Bean传入参数

ConfigurableBeanFactory

ConfigurableBeanFactory是一个可配置的BeanFactory。

方法 功能
setParentBeanFactory 设置父BeanFactory
setBeanClassLodaer 设置Bean的类加载器,默认是线程上下文类加载器
setTempClassLoader 设置暂时的,用于类型比较(TypeMatch)需求的类加载器
setCacheBeanMetadata 设置是否缓存Bean元数据
setBeanExpressionResolver 设置Bean表达式解析器,默认是null
addBeanPostProcessor 给工厂添加一个BeanPostProcessor,应用于该工厂创建的Bean上
registerAlias 为Bean注册别名
getMergedBeanDefinition 返回一个合并的BeanDefinition对象

这上面有一些东西我们不知道是啥,但是可以看出ConfigurableBeanFactory就是比BeanFactory多了一些配置信息。

AutowireCapableBeanFactory

一种有自动装配能力的BeanFactory。

方法 功能
createBean(Class) 创建Bean,并且填充所有带注解的字段
autowireBean(Object) 根据一个给定Bean对象,填充所有带注解的字段
configureBean(Object, String) 自动装载Bean属性,应用Bean属性值,调用工厂回调(如setBeanName),调用所有beanPostProcessor

其它的也都差不多,不全写上了。

ConfigurableListableBeanFactory

可配置的,列表的Bean工厂接口,它继承如下接口:

ListableBeanFactory,
AutowireCapableBeanFactory, 
ConfigurableBeanFactory

所以,它看起来支持获取Bean列表、有自动装载功能、可配置。

BeanDefinition

BeanDefinition接口是对一个Bean的描述,其中包含Bean的属性值、构造函数参数值等。对于特定的BeanDefinition实现,还可能有更多值。

方法 功能
getParentName 设置父definition的名字(如果有的话)
getBeanClassName 获取Bean类名
getScope 获取Bean作用域(Singleton/Prototype...)
isLazyInit 是否是懒加载Bean
getDependsOn 获取该bean依赖的bean名
isAutowireCandidate 该Bean是否是Autowire到其它Bean的候选对象
isPrimary 是否是Primary的Autowire候选者
getFactoryBeanName 获取FactoryBean的名字(如果有)
getFactoryMethodName 获取FactoryMethod的名字(如果有)
getConstructorArgumentValues 获取该Bean的构造方法参数值
getPropertyValues 获取该Bean的属性值
getInitMethodName 获取初始化方法的名字(init-method)
getDestroyMethodName 获取销毁方法的名字
... ...

DefaultListableBeanFactory类的使用

简单看看该类的层次结构

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
		implements ConfigurableListableBeanFactory, BeanDefinitionRegistry

尽管还是有很多抽象类和接口我们没看过,但是有了前面的知识,我们可以猜到该类具有自动装载能力,是一个可配置的、Listable的AutowireCapable的类,同时,它还是一个BeanDefinition注册处,意思是它里面能注册BeanDefinition。

光看各种各样的接口而没有一点实战很容易让人发懵,下面我们通过探索该类的用法来更加深入的了解上面我们接触到的接口实际上起到了什么效果。

通过BeanDefinition注册Bean

在这个容器中,我们并不会使用像之前StaticListableBeanFactory那种直接add的方式来注册Bean,而是使用BeanDefinition注册Bean。

我们有这样的两个类,我们最终要做到的就是,将它们两个注册到BeanFactory中,并且使用自动装载功能来将Person装载到Workbench中。

@Data
public class Person {
    private String name;
}

@Data
public class Workbench {
    private Person operator;
}

你可能疑惑为什么Workbenchoperator属性上没有@Autowire注解,这样能自动装载吗?答案是能的!在单独使用BeanFactory时(而不是具有自动扫描功能的ApplicationContext时),这个@Autowire注解没啥用。稍后源码分析阶段我们会看到,所有的未被满足并且没被依赖检查排除在外的属性都会被自动装载。

创建一个BeanDefinition,Bean的类是Person类:

RootBeanDefinition personRbd = new RootBeanDefinition(Person.class);

给BeanDefinition设置PropertyValues,稍后创建Bean时将这里给定的属性注入:

MutablePropertyValues pvs = new MutablePropertyValues();
pvs.addPropertyValue("name", "Yudoge");
personRbd.setPropertyValues(pvs);

设置Bean作用域,设置它可以作为Autowire的候选者:

personRbd.setScope(BeanDefinition.SCOPE_SINGLETON);
personRbd.setAutowireCandidate(true);

向BeanFactory中注册BeanDefinition:

factory.registerBeanDefinition("person", personRbd);

这样,这个BeanDefinition就被注册到了BeanFactory中

所以,BeanDefinition就像Bean的模板,它被注册到BeanFactory中,然后getBean时以它为模板创建对应的Bean

使用Autowire自动装载

接下来创建Workbench的BeanDefinition:

RootBeanDefinition workbenchRbd = new RootBeanDefinition(Workbench.class);
workbenchRbd.setScope(BeanDefinition.SCOPE_SINGLETON);
workbenchRbd.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);

向BeanFactory中注册,并调用factory.getBean来获取这个Bean:

factory.registerBeanDefinition("workbench", workbenchRbd);
Workbench workbench = factory.getBean(Workbench.class);
System.out.println(workbench);

img

总结

  • BeanDefinition是对于Bean的描述,包括Bean的类型、构造方法参数值、属性参数值、作用域、自动装载相关配置等
  • 一些实现了BeanDefinitionRegistry的BeanFactory一般都是使用BeanDefinition来注册Bean,BeanDefinition相当于Bean的模板,它被注册到BeanFactory中,等创建时使用这个模板创建
  • 实现了AutowireCapableBeanFactory的类可以执行Bean之间依赖的自动装载

创建Bean流程

实际上,对于DefaultListableBeanFactory来说,实际创建Bean的过程是在getBean时,getBean调用了resolveBean,我们直接看resolveBean

img

看起来很多,但仔细看过就不难发现,只有前面三行是我们需要关心的,前面三行是在当前BeanFactory中查找Bean,而后面都是在当前工厂中没有这个Bean时去父工厂找的代码。所以,我们只需要关心第一行resovleNamedBean这个成员方法即可:

// 这里有根据类型解析出多个候选Bean名的情况
// 为了保持简单,我们目前只关心只选出唯一Bean名的情况
// 所以,大部分代码被我省略了,稍后我们可能还会拿回来分析
@SuppressWarnings("unchecked")
@Nullable
private <T> NamedBeanHolder<T> resolveNamedBean(
        ResolvableType requiredType, @Nullable Object[] args, boolean nonUniqueAsNull) throws BeansException {

    String[] candidateNames = getBeanNamesForType(requiredType);

    if (candidateNames.length == 1) {
        return resolveNamedBean(candidateNames[0], requiredType, args);
    }
    return null;
}

首先,根据类型获取候选的BeanName字符串数组,然后,我们只保留了只有一个候选BeanName的分支,它调用了resolveNamedBean的重载方法,这次,传入的参数中有Bean的名字:

@Nullable
private <T> NamedBeanHolder<T> resolveNamedBean(
        String beanName, ResolvableType requiredType, @Nullable Object[] args) throws BeansException {

    Object bean = getBean(beanName, null, args);
    if (bean instanceof NullBean) {
        return null;
    }
    return new NamedBeanHolder<T>(beanName, adaptBeanInstance(beanName, bean, requiredType.toClass()));
}

可以看到,在这个使用名字解析的resolveNamedBean方法中,已经获得了实际的Bean对象,也就是方法中的第一行getBean。这也确实证实了对于这个BeanFactory,Bean创建过程是在获取Bean时才发生的。

点到这个getBean中,这实际上就是BeanFactory接口中定义的方法而已,该方法被DefaultListableBeanFactory的父类的父类AbstractBeanFactory实现,实际上,它调用了它内部的doGetBean

// 这个方法足足有151行,我只选咱们关心的逻辑
protected <T> T doGetBean(
        String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
        throws BeansException {

    String beanName = transformedBeanName(name);
    Object beanInstance;

    // 这里明显是一种缓存,因为有Singleton对象的存在
    // 所以不可能每次BeanFactory都从BeanDefinition创建
    // 这里如果有缓存并且不需要用指定参数来构建Bean的话,就可以用缓存
    Object sharedInstance = getSingleton(beanName);
    if (sharedInstance != null && args == null) {
        beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    }
    else {
        // 省略代码:如果当前BeanFactory中不存在BeanDefinition,尝试去父BeanFactory中获取Bean...

        try {

            RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);

            // 省略代码:对当前Bean显式依赖的Bean进行初始化(Autowired不算)

            // 如果mbd是单例
            if (mbd.isSingleton()) {
                // 调用来自父类`DefaultSingletonBeanRegistry`的`getSingleton`方法
                sharedInstance = getSingleton(beanName, () -> {
                    // `getSingleton的回调,具体的回调逻辑我们还不知道
                    // 不过我猜测是那个Registry把我们返回的Bean给缓存了起来
                    try {
                        return createBean(beanName, mbd, args);
                    }
                    catch (BeansException ex) {
                        destroySingleton(beanName);
                        throw ex;
                    }
                });
                beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
            }
            // 省略代码:如果是Prototype等...

        catch (BeansException ex) {
        }
    }

    return adaptBeanInstance(name, beanInstance, requiredType);
}

在进入getSingleton之前,先说一下DefaultSingletonBeanRegistry明显就是一个注册处,在Spring中带Registry的都是,就像BeanDefinitionRegistry内部会使用某种数据结构保存你注册的BeanDefinition一样,DefaultSingltonBeanRegistry会使用某种数据结构保存你注册的Singleton Bean,下次再看到XXXRegistry的类脑袋里要有这种画面。

先看一下,这个方法进去直接锁了注册处中的singletonObjects这个成员变量:

img

而正如我们所猜测的,这个成员变量是用来保存beanName->单例Bean实例的缓存映射。

img

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    // 原来的代码也很多,这里我简化了一下:
    synchronized (this.singletonObjects) {
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null) {
            // 创建之前做点什么
            beforeSingletonCreation(beanName);
            try {
                // 这里调用传入的创建Bean对象的方法,接收创建出的对象
                singletonObject = singletonFactory.getObject();
                newSingleton = true;
            } finally {
                // 创建之后做点什么
                afterSingletonCreation(beanName);
            }
            if (newSingleton) {
                // 将新创建的对象加入缓存
                addSingleton(beanName, singletonObject);
            }
        }
        return singletonObject;
    }
}

可以看到,首先尝试从注册处的缓存里获取,如果没有,进入Bean创建阶段,这里主要是调用外部传入的lambda表达式来创建Bean,也有道理,因为创建Bean不应该是单例Bean注册处的职责,它的职责应该只是负责注册和维护这些单例Bean。当外部创建完,它会将它添加到缓存中,以便下次直接使用。

而外部传入的Lambda刚刚我们也看了,简化来说就是这样,只调用了createBean

sharedInstance = getSingleton(beanName, () -> {
    return createBean(beanName, mbd, args);
});

createBeanAbstractAutowireCapableBeanFactory实现的,也就是DefaultListableBeanFactory的直接父类所实现的,这个方法在AbstractBeanFactory中就有定义,但是AutowireCapableBeanFactory对它的定义做了扩展,即这个方法除了创建Bean、完成它的初始化工作外还必须填充被注解标注的属性:

// 没错,我又省略了大部分无关代码
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
        throws BeanCreationException {

    RootBeanDefinition mbdToUse = mbd;

    try {
        // 给BeanPostProcessor一个机会返回一个代理Bean实例
        Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
        if (bean != null) {
            return bean;
        }
    } catch (Throwable ex) {}

    try {
        Object beanInstance = doCreateBean(beanName, mbdToUse, args);
        return beanInstance;
    } /* 省略catch */
}

现在,我们先不用管BeanPostProcessor返回代理类那里,我们主要关心doCreateBean,我们已经可以看出,在AbstractAutowireCapableBeanFactory中对于Bean的创建以及属性的自动装载,都会落到这个方法上。

// 这个方法也有96行,我们还是省略不相关逻辑
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
        throws BeanCreationException {

    // Instantiate the bean.
    BeanWrapper instanceWrapper = null;
    instanceWrapper = createBeanInstance(beanName, mbd, args);

    Object bean = instanceWrapper.getWrappedInstance();

    // Initialize the bean instance.
    Object exposedObject = bean;

    // 省略对创建出来的bean的属性装载

    return exposedObject;
}

这里,并不是直接创建Bean,而是创建出一个BeanWrapper来包装Bean,不过我们知道Bean肯定在createBeanInstance中被创建出来,并且返回给上层调用。

这个方法呢,我也不进去了,跟踪到最后,就是直接调用构造器创建了Bean对象并包装到BeanWrapper中,但有一事要注意,如果Bean中只提供了一个使用@Autowired的构造函数,那么还得处理自动装载相关的事宜。

所以,到这里为止,BeanFactory创建Bean的代码分析就算完了。

总结

  1. 当你通过BeanDefinition注册Bean时,Bean并未被初始化,而是保存在BeanDefinitionRegistry的数据结构中
  2. DefaultListableBeanFactory的getBean被调用时,根据BeanDefinitionRegistry中的信息进行创建Bean
  3. 如果是SingletonBean,经过层层调用,最终来到DefaultSingletonBeanRegistry
  4. 单例Bean注册处检查是否有该单例bean的缓存,如果有就直接注册,否则回调BeanFactory进行创建
  5. AbstractAutowireCapableBeanFactorycreateBean方法会完成Bean的初始化,并且,会完成自动装配
  6. 对于非单例的PrototypeBean,最终也会回调到createBean上,但是由于每次都返回新对象,不用有一个类似DefaultSingletonBeanRegistry的缓存

本节只分析了DefaultListableBeanFactory的创建Bean过程,而且省略了很多在本节示例中并不关键的代码,这就是阅读第三方框架源码时应该做的,否则你会陷入一个又一个的调用的地狱之中。

本节的内容当然有限,不过我想通过本节,最起码我们可以学到Spring中的BeanFactory系列组件中,各个接口的责任,抽象类抽象了什么、简化了什么,注册处是什么、BeanDefinition是什么,更重要的是——如何阅读别人的代码。

本节也让我学到了很多很多,我之前从未读过体系这样复杂的代码,如果我所描述的有什么问题,欢迎留言指正。

好了,关于自动装载的流程,我想就留到明天早上来阅读吧,我也要去舔我的姐姐了~~

自动装载流程

上面我们分析了创建Bean的流程,那是在getBean时才调用的,而创建Bean里面有个自动装载Bean的过程,我们给省略了,我们现在就是要找回这部分内容。

首先,有了上面的经验,我们可以大胆猜测,自动装载Bean的过程可能会分以下几步:

  1. 获取Autowire注解,解析所有要注入的Bean
  2. 在BeanFactory(可能还包括父容器)中搜索那些要注入的Bean的BeanDefinition
  3. 通过BeanDefinition获取Bean,这里分为Singleton和ProtoType,如果是Prototype,那么需要创建这个Bean并注入
  4. 如果是Singleton,需要先看看注册处中有没有缓存这个Bean,如果有直接拿来注入
  5. 否则,创建这个Singleton Bean,插入到缓存并注入

回到AbstractAutowireCapableBeanFactorydoCreateBean方法,这次我们将之前省略掉的代码拿回来一些,关于自动装载,主要的部分就在这个populateBean调用上:

// 同样,我省略了很多很多代码,这些代码中有关于Bean生命周期函数的调用,如果有需要可以自己查看源代码
// 可能以后也会出关于Bean生命周期源码解析的文章,那里就会偏向于现在被省略的那些代码了
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
        throws BeanCreationException {

    BeanWrapper instanceWrapper = null;
    Object bean = instanceWrapper.getWrappedInstance();
    Object exposedObject = bean;

    try {
        // 装载Bean,传入如下参数
        // 1. bean名字
        // 2. mbd(合并后的BeanDefinition,我目前也不知道合并了啥,稍后会分析合并BeanDefinition的代码)
        // 3. BeanWrapper,BeanWrapper其中包含了Bean对象
        populateBean(beanName, mbd, instanceWrapper);
        exposedObject = initializeBean(beanName, exposedObject, mbd);
    }
    catch (Throwable ex) {}

    return exposedObject;
}

什么?我为什么知道是populateBean?因为AutowireCapableBeanFactory的文档注释中就关根据注解装载Bean属性这一行为用单词populate来描述。

img

下面我们来看看populateBean的代码:

// 省略后的代码
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {


    PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);

    int resolvedAutowireMode = mbd.getResolvedAutowireMode();
    if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
        MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
        // Add property values based on autowire by name if applicable.
        if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
            autowireByName(beanName, mbd, bw, newPvs);
        }
        // Add property values based on autowire by type if applicable.
        if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
            autowireByType(beanName, mbd, bw, newPvs);
        }
        pvs = newPvs;
    }

}

主要就是根据BeanDefinition获取属性,然后根据Bean的自动装载类型选择一个autowireByNameautowireByType,根据我们对接口的了解,这两个方法是AutowireCapableBeanFactory中的,我们使用的是autowireByType

进入autowireByType,由于代码比较长,我在代码上打上注解:

protected void autowireByType(
        String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {

    // 获取类型转换器,这里获取到的是Null,然后使用BeanWrapper作为类型转换器,所以BeanWrapper肯定实现了TypeConverter
    TypeConverter converter = getCustomTypeConverter();
    if (converter == null) {
        converter = bw;
    }

    // 获取所有未满足的非简单属性并对其进行遍历,非简单的意思是不包括原始类型和字符串类型这样的简单属性
    // 所以,我们的待自动装载的属性operator肯定会在这里
    Set<String> autowiredBeanNames = new LinkedHashSet<>(4);
    /*
    未满足的简单属性必须:
        1. 具有get方法
        2. 没有被依赖检查排除(通过factory的ignoreDependencyType设置,String默认就被排除了)
        3. 该属性目前没有值
        4. 不是简单类型的属性(Void, Enum, CharSequence, Number, Date, Temporal, URI, URL, Locale, Class)
    */
    String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
    for (String propertyName : propertyNames) {
        try {
            // 获取该未满足属性的描述符
            PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
            // 即使从技术上来说,Object算是一个未满足的非简单属性,但是对一个Object类型的属性进行自动装配永远没有意义
            // 从这里可以看出,该BeanFactory会忽略所有Object类型属性上的自动装配
            if (Object.class != pd.getPropertyType()) {
                // 获取该属性的set方法参数
                MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
                // 获取自动注入的依赖描述
                DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
                // 解析依赖,获得依赖的对象
                Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
                // 如果解析到的依赖不是null,就把它放到该bean的pvs中
                if (autowiredArgument != null) {
                    pvs.add(propertyName, autowiredArgument);
                }
                // 注册依赖关系
                for (String autowiredBeanName : autowiredBeanNames) {
                    registerDependentBean(autowiredBeanName, beanName);
                    if (logger.isTraceEnabled()) {
                        logger.trace("Autowiring by type from bean name '" + beanName + "' via property '" +
                                propertyName + "' to bean named '" + autowiredBeanName + "'");
                    }
                }
                autowiredBeanNames.clear();
            }
        }
        catch (BeansException ex) {
            throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex);
        }
    }
}

所以,关键的关键落到了resolveDependency这个方法上,它负责根据上面计算出的一些描述信息、转换器等工具,还有Bean名,被自动装载的Bean名来解析依赖。

resolveDependency无论是在AbstractBeanFactoryAbstractAutowireCapableBeanFactory中都没有实现,这是典型的模板设计模式,它们因为由于无法确定该方法实现的细节所以留了一个代码桩(Stub),也就是抽象方法,然后子类去实现该抽象方法。那么该方法一定在DefaultListableBeanFactory中了:

@Override
@Nullable
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
        @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {

    descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
    // 依赖类型是否是Optional
    if (Optional.class == descriptor.getDependencyType()) {
        return createOptionalDependency(descriptor, requestingBeanName);
    }
    // 依赖类型是否是ObjectFactory或ObjectProvider
    else if (ObjectFactory.class == descriptor.getDependencyType() ||
            ObjectProvider.class == descriptor.getDependencyType()) {
        return new DependencyObjectProvider(descriptor, requestingBeanName);
    }
    // 依赖类型是否是这个什么javaxInjectProviderClass
    else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
        return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
    }
    // 对于上面的三个,显然我们都会跳过,我们的示例走的是最后一个else
    else {
        // 这里调用了一个AutowireCandidateResovler,也就是自动装载候选者解析器
        // 并且调用了它的一个名字叫“如果必要,获取惰性解析代理”的方法,这可能是用来支持某些懒加载属性的吧,我们肯定没用上
        Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
                descriptor, requestingBeanName);
        // 我们的代码走了这里,调用了doResolveDependency
        if (result == null) {
            result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
        }
        return result;
    }
}

怎么感觉没头呢,这代码。。。

@Nullable
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
        @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {

    try {
        // 这里应该是解析了一个什么快照,如果从这里能直接获取到,就不必执行下面的逻辑了,直接返回
        Object shortcut = descriptor.resolveShortcut(this);
        if (shortcut != null) {
            return shortcut;
        }
        
        // 获取依赖类型
        Class<?> type = descriptor.getDependencyType();
        // 获取是否建议使用默认值,通常返回一个字符串表达式,如果没找到反掌null
        Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
        if (value != null) {
            // 由于我们的代码里没用这些东西,所以我省略了
        }

        // 我也不知道这是干啥的,官方源码里没有一点注释,但是我们的示例没有走这里就对了
        Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
        if (multipleBeans != null) {
            return multipleBeans;
        }

        // 获取候选,这里Map的值Object可能是候选对象的Class,从代码上看也可能直接就是候选对象的实例
        // 不过我们的示例中,这里是候选对象的Class,也就是Person.class
        Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);

        // 将被注入的bean的名字
        String autowiredBeanName;
        // 候选对象的实例
        Object instanceCandidate;

        // 如果候选对象大于1个,那么需要决定哪个bean被注入,直到这里操作的都是候选Bean的类对象
        if (matchingBeans.size() > 1) {
            // 省略
        }
        else {
            // 只有一个候选对象
            Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
            // 根据matchingBean的唯一项来设置autowiredBeanName和instanceCandidate
            autowiredBeanName = entry.getKey();
            instanceCandidate = entry.getValue();
        }

        // 如果这个候选对象实例是一个类(我们这里就是,是Person.class),调用`resovleCandidate`将它实例化
        if (instanceCandidate instanceof Class) {
            instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
        }
        // 返回
        Object result = instanceCandidate;
        // ...

        return result;
    }
    finally {
        ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
    }
}

所以,问题又落在了DependencyDescriptor类的resolveCandidate方法上,我盲猜一会儿还有doResolveCandidate,它们不会让我们消停。

卧槽!!!!竟然没有,它的实现竟然这么简单:

public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory)
        throws BeansException {

    return beanFactory.getBean(beanName);
}

它只调用了beanFactorygetBean来获取Bean,getBean方法是我昨天分析过的,也就是上一个小节“创建Bean流程”中所讲解的。接下来的事我们也知道了,如果该bean的beandefinition上面指定它是prototype,那么就创建它并返回,否则查看Singleton注册处中是不是已经有了这个Bean,有就直接返回,没有创建。这下,整个流程结束了。

总结

其实这整个流程说复杂也复杂,说简单也简单,复杂就复杂在,代码在它的几个BeanFactory的继承关系中来回跳入跳出,各种方法互相调用。而简单就简单在背后的逻辑其实没什么复杂的。

  1. getBean时,AbstractAutowireCapableBeanFactory在实例化完这个Bean时会调用populateBean来对它其中的需要自动装载的属性进行装载
  2. 它会根据该Bean的BeanDefinition选择调用autowireByTypeautowireByName
  3. 这两个方法会读取所有待注入的,未满足的简单属性(Unsatisfied Non-Simple Properties)的属性名,并按照自己的逻辑进行注入

    所以,如果只使用BeanFactory的话,属性是否被自动装载与是否打上@Autowire注解无关。只要是未满足简单属性,并且它没被从依赖检查中排除(isExcludedFromDependencyCheck),它就会被自动装载。

  4. autowireByName不是我们代码中选择的方式,而且它也比较简单,只是简单的又直接调用了getBean来获取依赖的Bean
  5. autowireByType要处理的逻辑复杂一点,它需要根据类型寻找Bean,并且还要处理Bean冲突的问题(找出了多个Bean)
  6. 对于每个依赖的bean,autowireByType调用resolveDependency来解析依赖
  7. resolveDependency的实现定义在具体的子类中,我们所观察的子类是DefaultListableBeanFactory,它针对Optional、ObjectFactory、ObjectProvider等类型的Bean有特殊处理,并且它支持返回一个Bean的懒加载代理
  8. resolveDependency调用了doResolveDependency,这里解决获取依赖Bean冲突的问题,在一切正常的情况下,它会调用DependencyDescriptor.resolveCandidate方法来获取候选Bean,该方法只是简单的调用了BeanFactory.getBean,所以说一切又回到了getBean上。
  9. 也许某些DependencyDescriptor的子类会重写这个方法,来修改该方法的行为

所以,自动注入流程也没啥复杂的,说白了,就对于所有它需要自动装载的Bean,调用getBean来获取Bean并装载进去。这其中可能涉及到一些Bean冲突的发现、解决。

posted @ 2022-07-12 18:42  yudoge  阅读(318)  评论(0编辑  收藏  举报