likes
comments
collection
share

【重写SpringFramework】第一章beans模块:填充对象(chapter 1-6)

作者站长头像
站长
· 阅读数 22

1. 前言

在对象实例化之后,我们需要对一些字段进行赋值,这一过程称之为对象的填充(populate)。填充对象由两部分组成,一是属性访问,二是自动装配(autowire)。属性访问的功能已经介绍过了,本节主要讨论的是自动装配的问题。自动装配也称依赖注入,包括两个部分,即环境变量解析和对象解析,主要有三点区别:

  • 一是注解不同,环境变量解析只使用 @Value 注解,对象解析使用 @Autowired@Resource@Inject 等注解。
  • 二是依赖项的来源不同,环境变量解析的依赖项来自 Enviroment 的某个属性值,对象解析的依赖项来自 Spring 容器中的单例。
  • 三是注入方式不同,环境变量解析只能通过字段注入,对象解析可以使用字段注入或 setter 方法注入。

无论是环境变量解析,还是对象解析,最终都要通过依赖解析的功能,完成依赖项的查找和注入。依赖解析分为三种,嵌入值处理仅用于环境变量的解析,集合类型和单一类型的解析则用于对象解析。

【重写SpringFramework】第一章beans模块:填充对象(chapter 1-6)

2. 自动装配原理

2.1 注入目标

关于依赖注入,我们可以从两个角度来审视。首先,从注入目标来说,可以分为两种:一是字段,二是方法参数。示例代码演示了对象解析的两种方式,一是字段注入,@Autowired 注解声明在字段上。二是 setter 方法注入,@Autowired 注解声明在 setter 方法上,实际注入的是方法参数 bar

//示例代码:注入目标为字段
public class Foo {
    @Autowired
    private Bar bar;
}

//示例代码:注入目标为方法参数
public class Foo {
    private Bar bar;

    @Autowired
    public void setBar(Bar bar) {
        this.bar = bar;
    }
}

对于环境变量和对象解析来说,都可以通过字段注入的方式设置依赖项。示例代码如下,@Value 注解声明在 profile 字段上,表明该字段的值来自环境变量。@Autowired 注解声明在自定义对象上,表明该字段的值来自容器托管的单例。既然环境变量和对象解析都可以进行字段注入,那么基本逻辑是相同的。本节主要介绍环境变量的解析过程,并以此作为对象解析的基础。

//示例代码:字段注入
public class Foo {
    @Value("${spring.profiles.active}")
    private String profile;
    @Autowired
    private Bar bar;
}

2.2 DependencyDescriptor

Spring 对注入目标进行了抽象,使用 DependencyDescriptor 来描述一个字段或方法参数的依赖信息,从这个角度来看,该类与 BeanDefinition 的作用是相似的。

  • containingClass:注入目标所属的具体类
  • field:表明注入目标是一个字段(与方法参数二选一)
  • methodParameter:表明注入目标是一个方法参数(与字段二选一)
  • nestingLevel:嵌套层级,简单类型的层级为 1,泛型集合或数组的层级大于 1,比如 List<String> 的层级为 2
  • required:依赖项是否必须存在,如果为 true 且没有找到依赖项则报错
  • fieldAnnotations:声明在字段上的注解
  • resolvableType:如果依赖类型是集合或数组,则需要得到元素的类型
public class DependencyDescriptor {
    private Class<?> containingClass;
    private Field field;
    private MethodParameter methodParameter;
    private int nestingLevel = 1;
    private final boolean required;
    private volatile Annotation[] fieldAnnotations;
    private volatile ResolvableType resolvableType;
}

2.3 InjectionMetadata

注入目标决定了注入方式,InjectionMetadata 表示一个类的注入元数据,所谓元数据是指这个类所有需要注入的元素的信息。targetClass 字段表示目标对象,也就是 BeanFactory 正在处理的实例。injectedElements 字段表示需要注入的元素,由于一个对象可能有多个字段或方法参数需要注入,因此该字段是集合类型。

public class InjectionMetadata {
    private final Class<?> targetClass;
    private final Collection<InjectedElement> injectedElements;

    public static abstract class InjectedElement{
        protected final Member member;
        protected final PropertyDescriptor pd;

        protected abstract void inject(Object bean, String beanName) throws Throwable;
    }
}

InjectedElement 作为内部抽象类,作用是描述一个注入的元素。member 字段表示类的成员,在这里指字段和方法。AutowiredAnnotationBeanPostProcessor 组件定义了 InjectedElement 的两个子类,其中 AutowiredFieldElement 表示注入到字段上,AutowiredMethodElement 表示注入 setter 方法。

【重写SpringFramework】第一章beans模块:填充对象(chapter 1-6)

3. BeanPostProcessor

3.1 概述

俗话说一个好汉三个帮,Spring 容器的强大功能离不开各种组件的支持。BeanPostProcessor 提供了若干钩子方法,在 Spring 容器创建对象的不同阶段进行回调。BeanPostProcessor 不仅被 Spring 框架使用,同时作为面向用户的扩展接口,允许开发者进行自定义的操作。BeanPostProcessor 的出现,极大地丰富了 Spring 容器的操作空间,很多重要的功能都是由该组件完成的。

3.2 核心 API

BeanPostProcessor 接口定义了在 Bean 的初始化前后进行处理的方法,也就是说该接口的调用时机是在初始化阶段,目前处于填充对象的流程,我们将在之后的对象的初始化流程介绍具体的用法。

  • postProcessBeforeInitialization 方法:在对象初始化前执行
  • postProcessAfterInitialization 方法:在对象初始化后执行
public interface BeanPostProcessor {
    Object postProcessBeforeInitialization(Object bean, String beanName);
    Object postProcessAfterInitialization(Object bean, String beanName);
}

本节我们关心的是它的子接口 InstantiationAwareBeanPostProcessor,从类名可以看到,该接口的关注点是对象的实例化过程。

  • postProcessPropertyValues 方法的调用时机是在填充对象的过程中。
  • postProcessBeforeInstantiation 方法的调用时机是在创建对象之前,尝试返回一个代理对象。
public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {
    //完成定制的依赖注入和依赖检查,比如@Autowired、@Resource、@PersistContext
    void postProcessPropertyValues(Object bean, String beanName);
    //在实例化对象之前调用,返回的可能是一个代理
    Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException;
}

AutowiredAnnotationBeanPostProcessor 作为 InstantiationAwareBeanPostProcessor 接口的实现类,通过注解声明的方式提供自动装配的功能。

  • autowiredAnnotationTypes 字段表示支持自动装配的注解集合
  • injectionMetadataCache 字段的作用是缓存已解析的注入元数据

在构造方法中,默认添加了三个支持自动装配的注解,其中 @Autowired@Value 是 Spring 框架定义的,@Inject 注解是 JDK 定义的。由于 @Inject 注解所属的 javax.inject 是一个扩展包,应用程序可能不会引用该包,因此只能尝试获取该注解,有可能不存在。

public class AutowiredAnnotationBeanPostProcessor implements InstantiationAwareBeanPostProcessor, PriorityOrdered {

    private final Set<Class<? extends Annotation>> autowiredAnnotationTypes = new LinkedHashSet<>(4);
    private final Map<String, InjectionMetadata> injectionMetadataCache = new ConcurrentHashMap<>(256);

    public AutowiredAnnotationBeanPostProcessor(){
        this.autowiredAnnotationTypes.add(Autowired.class);
        this.autowiredAnnotationTypes.add(Value.class);

        //兼容@Inject注解
        try {
            this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
                    ClassUtils.forName("javax.inject.Inject", getClass().getClassLoader()));
        }catch (ClassNotFoundException ex) {}
    }
}

3.3 相关调整

ConfigurableBeanFactory 接口定义了与 BeanPostProcessor 有关的方法,AbstractBeanFactory 类的 beanPostProcessors 字段用于缓存 BeanPostProcessor 组件。

public interface ConfigurableBeanFactory {
    void addBeanPostProcessor(BeanPostProcessor beanPostProcessor);
    int getBeanPostProcessorCount();
}

public abstract class AbstractBeanFactory {
    private final List<BeanPostProcessor> beanPostProcessors = new CopyOnWriteArrayList<>();
}

4. createBean 方法

4.1 实例化前创建代理

回到 AbstractAutowireCapableBeanFactorycreateBean 方法,在真正创建对象之前,提供一个机会来尝试获取代理对象。如果代理对象存在,则不执行 doCreateBean 方法。但这并不是创建代理对象的主流方式,相关内容将在第二章 aop 模块中介绍,仅了解。

//所属类[cn.stimd.spring.beans.factory.support.AbstractAutowireCapableBeanFactory]
//创建Bean的流程
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd) {
    //尝试创建代理对象
    Object bean = applyBeanPostProcessorsBeforeInstantiation(beanName, mbdToUse);
    if (bean != null) {
        return bean;
    }

    return doCreateBean(beanName, mbdToUse);
}

4.2 填充对象

接下来是 doCreateBean 方法的调整,执行完第一步之后,得到了一个空的对象,在第三步填充对象中设置若干属性,使对象变得可用。

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, Object[] args) {
    //1. Bean的实例化(略)
    //2. 提前暴露Bean以解决循环依赖(TODO)

    //3. 填充对象
    populateBean(beanName, mbd, instanceWrapper);
    //4. 初始化(TODO)
}

populateBean 方法实现了自动装配和属性访问的功能,其中属性访问已经详细介绍过了,我们重点关注自动装配是如何实现的。首先遍历容器中的 BeanPostProcessor 集合,找到 InstantiationAwareBeanPostProcessor 接口的实现类,调用 postProcessPropertyValues 方法来处理属性值。

//填充属性
protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
    //1. 自动装配,处理@Autowired、@Value、@Inject等注解
    if(!mbd.isSynthetic()){
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof InstantiationAwareBeanPostProcessor) {
                InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                ibp.postProcessPropertyValues(bw.getWrappedInstance(), beanName);
            }
        }
    }

    //2. 属性访问,通过BeanWrapper为字段赋值
    PropertyValues pvs = mbd.getPropertyValues();
    if (pvs != null) {
        bw.setPropertyValues(pvs);
    }
}

5. 自动装配

5.1 概述

自动装配的流程分为两个阶段,我们结合时序图来分析第三步和第四步。第一阶段对注入目标进行解析。AutowiredAnnotationBeanPostProcessor 检查对象的字段或方法是否声明了 @Value@Autowired 等注解,如果存在,则将注入目标和依赖信息包装成 InjectionMetadataDependencyDescriptor。第二阶段寻找依赖项,并赋给注入目标。这一过程是由 Spring 容器完成的。这一点也很好理解,因为 Spring 容器掌握着所有的资源,便于寻找依赖项。

【重写SpringFramework】第一章beans模块:填充对象(chapter 1-6)

5.2 注入目标解析

AutowiredAnnotationBeanPostProcessor 实现了 postProcessPropertyValues 方法,完成了自动装配的流程。该方法可以分为两步,首先获取注解元数据,所有声明了 @Autowired 等注解的字段和方法都被包装成 InjectionMetadata。然后执行注入操作,遍历所有的 InjectedElement,依次进行依赖注入。

@Override
public void postProcessPropertyValues(Object bean, String beanName) {
    InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass());
    metadata.inject(bean, beanName);
}

第一步,寻找自动装配的元数据。findAutowiringMetadata 方法主要对缓存进行处理,真正的构建工作是由 buildAutowiringMetadata 方法完成的。

//寻找自动装配的元数据
private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz) {
    String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
    InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
    //如果缓存中没有InjectionMetadata,则构建新的实例
    if(metadata == null){
        metadata = buildAutowiringMetadata(clazz);
        this.injectionMetadataCache.put(cacheKey, metadata);
    }
    return metadata;
}

do...while 的循环中遍历对象及其父类,检查字段或者方法上是否声明了有关依赖注入的注解,具体流程如下:

  1. 调用 ReflectionUtils 工具类的 doWithLocalFields 方法,以反射的方式得到当前对象的所有字段和方法
  2. 调用 findAutowiredAnnotation 方法检查字段上是否声明了相关注解,如果存在,则包装成 AutowiredFieldElement 实例,并添加到集合中
  3. 继续检查方法上是否声明了相关等注解,如果存在,则包装成 AutowiredMethodElement 实例,并添加到集合中(代码略)
  4. 构建 InjectionMetadata 对象,返回注解元数据
//构建自动装配的元数据
public InjectionMetadata buildAutowiringMetadata(final Class<?> clazz){
    LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<>();
    Class<?> targetClass = clazz;

    //遍历Bean及其父类上的字段和方法
    do {
        //检查字段上是否有@AutoWired、@Inject等注解
        ReflectionUtils.doWithLocalFields(targetClass, field -> {
            AnnotationAttributes attrs = findAutowiredAnnotation(field);
            if(attrs != null){
                boolean required = determineRequiredStatus(attrs);
                elements.add(new AutowiredFieldElement(field, required));
            }
        });

        //检查方法上是否有@AutoWired、@Inject等注解(略)

        targetClass = targetClass.getSuperclass();
    }
    while(targetClass != null & targetClass != Object.class);
    return new InjectionMetadata(clazz, elements);
}

第二步,得到 InjectionMetadata 对象之后,执行注入操作。inject 方法的逻辑很简单,将真正的注入工作委托给 injectedElements 集合中的元素。

public class InjectionMetadata {

    public void inject(Object target, String beanName) throws Throwable {
        for (InjectedElement element : this.injectedElements) {
            element.inject(target, beanName);
        }
    }
}

注入目标分为字段和方法,两者的实现基本一致,我们以 AutowiredFieldElement 为例说明。inject 方法分为三步,第二步依赖解析最为关键。

  1. 准备工作,需要创建一个 DependencyDescriptor 对象,包含了依赖的相关信息
  2. 调用 AutowireCapableBeanFactory 接口的 resolveDependency 方法对依赖进行解析,返回结果可能是一个对象,也可能是基本类型(字符串等)
  3. 通过反射的方式将解析后的值赋给字段
private class AutowiredFieldElement extends InjectionMetadata.InjectedElement{

    @Override
    protected void inject(Object bean, String beanName) throws Throwable{
        Field field = (Field) this.member;
        Object value;

        //创建依赖描述符
        DependencyDescriptor desc= new DependencyDescriptor(field, this.required);
        desc.setContainingClass(bean.getClass());

        //对依赖进行解析,如果Bean不存在则创建并加入到IOC容器中
        value = beanFactory.resolveDependency(desc, beanName);

        //使用反射为字段赋值
        if(value != null){
            ReflectionUtils.makeAccessible(field);
            field.set(bean, value);
        }
    }
}

5.3 依赖解析

从上述代码可以看到,AutowiredAnnotationBeanPostProcessor 负责对单例进行分析,找出所有需要注入的元素,最核心的依赖解析交还给 Spring 容器处理。这一点也很好理解,因为 Spring 容器掌握着所有的资源,便于寻找符合条件的依赖项。AutowireCapableBeanFactory 接口声明了 resolveDependency 方法,负责寻找依赖项。

public interface AutowireCapableBeanFactory extends BeanFactory {
    Object resolveDependency(DependencyDescriptor descriptor, String requestingBeanName) throws BeansException;
}

DefaultListableBeanFactory 类实现了 resolveDependency 方法,实际上 resolveDependency 方法只是做了一些外围工作,具体流程是由 doResolveDependency 方法完成的。该方法的逻辑比较复杂,我们先来看一下总体流程,分为以下三步:

  1. 环境变量的解析,也就是处理 @Value 注解
  2. 集合类型的依赖,比如 List<T>
  3. 单一对象依赖,这是依赖解析的核心,因为集合类型的依赖可以分解成单一类型依赖
private Object doResolveDependency(DependencyDescriptor descriptor){
    //1. 环境变量解析
    //2. 集合类型依赖
    //3. 单一对象依赖
}

6. 环境变量解析

6.1 概述

所谓环境变量是指应用程序在运行过程中所依赖的参数信息,它们来自操作系统、配置文件等多种途径。Spring 核心包提供了 Environment 接口对环境变量进行抽象。我们经常需要引用某些参数,常规做法是获取 Environment 对象并调用 getProperty 方法。此外,Spring 提供了 @Value 注解简化这一操作,在字段上声明该注解,由 Spring 容器将对应的参数注入到字段上。

6.2 代码实现

回到 DefaultListableBeanFactory 类的 doResolveDependency 方法,第一步就是环境变量的解析,也就是处理 @Value 注解。整个过程比较简单,分为以下三步:

  • 获取 @Value 注解上的 value 属性值,格式为 ${xxx}
  • 解析占位字符串对应的参数,具体逻辑由 StringValueResolver 接口的实现类完成
  • 进行类型转换并返回
//所属类[cn.stimd.spring.beans.factory.support.DefaultListableBeanFactory]
//依赖解析
private Object doResolveDependency(DependencyDescriptor descriptor){
    //1. 处理@Value注解
    //获取注解上的value属性值
    Object value = this.autowireCandidateResolver.getSuggestedValue(descriptor);
    if (value != null) {
        if(value instanceof String){
            //使用StringValueResolver解析占位符参数
            value = resolveEmbeddedValue((String) value);
        }
        //类型转换
        return getTypeConverter().convertIfNecessary(value, descriptor.getDependencyType(), descriptor.getField());
    }
    ...
}

这里用到了 AutowireCandidateResolverStringValueResolver 两个组件。需要注意的是,Spring 没有直接提供 StringValueResolver 接口的实现类,而是通过创建匿名类的方式,将参数占位符的解析交给 Environment 对象处理。示例代码如下:

//示例代码:添加一个StringValueResolver,用于解析环境变量
public void addStringValueResolver() {
    DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
    StandardEnvironment environment = new StandardEnvironment();

    //添加字符串值解析器
    factory.addEmbeddedValueResolver(new StringValueResolver() {
        @Override
        public String resolveStringValue(String strVal) {
            //委托给环境变量处理
            return environment.resolvePlaceholders(strVal);
        }
    });
}

6.2 AutowireCandidateResolver

AutowireCandidateResolver 接口的作用是对候选项进行解析,环境变量的解析是通过 getSuggestedValue 方法完成的。

  • isAutowireCandidate 方法:判断指定 BeanDefinition 是否为依赖项
  • getSuggestedValue 方法:获取建议的值,该方法是为 @Value 注解量身定做的
  • isRequired 方法:判断一个依赖项是否必须,如果为 true,当依赖项不存在时抛出异常
public interface AutowireCandidateResolver {
    boolean isAutowireCandidate(BeanDefinitionHolder holder, DependencyDescriptor descriptor);
    Object getSuggestedValue(DependencyDescriptor descriptor);
    boolean isRequired(DependencyDescriptor descriptor);
}

DefaultListableBeanFactory 持有一个 AutowireCandidateResolver 类型的字段,使用 QualifierAnnotationAutowireCandidateResolver 作为默认实现。

public class DefaultListableBeanFactory {
    private AutowireCandidateResolver autowireCandidateResolver = new QualifierAnnotationAutowireCandidateResolver();
}

6.3 StringValueResolver

StringValueResolver 接口是 Spring 核心包提供的组件,作用是对字符串类型的值进行解析。ConfigurableBeanFactory 接口定义了管理 StringValueResolver 的相关方法,AbstractBeanFactory 则持有一个 StringValueResolver 的集合。

public interface ConfigurableBeanFactory {
    void addEmbeddedValueResolver(StringValueResolver valueResolver);
    boolean hasEmbeddedValueResolver();
    String resolveEmbeddedValue(String value);
}


public abstract class AbstractBeanFactory {
    //字符串值解析器的缓存
    private final List<StringValueResolver> embeddedValueResolvers = new LinkedList<>();
}

7. 测试

7.1 属性访问

之前我们单独测试过属性访问的功能,现在是把 BeanWrapper 整合到在 Spring 容器创建对象的整个流程中进行考察。

public class AutowireConfig {
    private String name;

    //getter/setter方法略
}

在测试方法中,首先创建 RootBeanDefinition 对象,然后添加属性值。接下来创建了 BeanFactory 的实例,并将 RootBeanDefinition 注册到容器中。最后调用 getBean 方法,在创建目标对象的过程中,完成了属性访问的操作。

@Test
public void testPropertyValues(){
    RootBeanDefinition beanDefinition = new RootBeanDefinition(AutowireConfig.class);
    beanDefinition.getPropertyValues().addPropertyValue("name", "Stimd");

    DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
    factory.registerBeanDefinition("autowireConfig", beanDefinition);

    AutowireConfig autowireConfig = factory.getBean("autowireConfig", AutowireConfig.class);
    System.out.println("PropertyValues注入测试:name的值为" + autowireConfig.getName());
}

从测试结果可以看到,BeanDefinition 中预先设置的属性值赋给了 BeanFactory 创建的对象,符合预期。

PropertyValues注入测试:name的值为Stimd

7.2 环境变量解析

在测试类中,profile 属性有着特殊的含义,它代表了应用程序的运行环境,常见的有开发、测试、生产等环境。不同的运行环境下可以进行相应的设置,比如连接不同的数据库。

public class AutowireConfig {
    @Value("${spring.profiles.active}")
    private String profile;

    public String getProfile() {
        return this.profile;
    }
}

测试方法稍微有点复杂,可以分为以下几步:

  1. 创建 BeanFactory 实例,并将 AutowiredAnnotationBeanPostProcessor 注册到容器中。
  2. 模拟环境变量,创建 StandardEnvironment 对象,并添加一个配置项。
  3. 创建匿名的 StringValueResolver 对象,resolveStringValue 方法的逻辑是从环境变量中检索指定的 key 所对应的 value。
  4. 创建 RootBeanDefinition 对象,并注册到容器中,然后调用 getBean 方法,在创建对象的过程中完成环境变量的解析。
//测试方法
@Test
public void testResolveEnvironment(){
    //添加解析@Value的BeanPostProcessor
    DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
    AutowiredAnnotationBeanPostProcessor processor = new AutowiredAnnotationBeanPostProcessor();
    processor.setBeanFactory(factory);
    factory.addBeanPostProcessor(processor);

    //模拟环境变量
    StandardEnvironment environment = new StandardEnvironment();
    environment.getSystemProperties().put("spring.profiles.active", "dev");

    //添加StringValueResolver
    factory.addEmbeddedValueResolver(new StringValueResolver() {
        @Override
        public String resolveStringValue(String strVal) {
            return environment.resolvePlaceholders(strVal);
        }
    });

    factory.registerBeanDefinition("autowireConfig", new RootBeanDefinition(AutowireConfig.class));
    AutowireConfig autowireConfig = factory.getBean(AutowireConfig.class);
    System.out.println("@Value测试,profile的值为" + autowireConfig.getProfile());
}

从测试结果可以看到,环境变量对象中的属性值,通过 @Value 注解读取了出来,符合预期。

环境变量解析测试,profile的值为dev

8. 总结

本节介绍了填充对象的基本流程,包括两个方面,一是属性访问,通过 PropertyAccessor 组件将属性值赋给对象。二是自动装配,为声明了指定注解的字段或方法寻找合适的依赖项。二者的区别在于,属性访问的数据通常是事先指定的,自动装配的依赖项来源于 Spring 容器所管理的资源,包括单例和环境变量等。之前已经讲解过属性访问,本节重点关注自动装配的实现。

自动装配的流程分为两步,首先对注入目标进行解析,具体工作是由 AutowiredAnnotationBeanPostProcessor 组件完成的,负责解析一个类的注入信息。其次,对依赖项进行解析,并注入到对应的目标上。寻找依赖项的过程是由 Spring 容器完成的,主要处理了两种情况:

  • 环境变量解析:负责处理 @Value 注解,通过 StringValueResolver 组件寻找环境变量中指定的属性。
  • 对象解析:负责处理 @Autowired@Inject 等注解,在 Spring 容器中寻找符合条件的单例。

本节实现了环境变量的解析,完成了自动装配的基本流程。虽然环境变量解析仅涉及字段注入,但和 setter 方法注入的流程是一样的,只是在具体注入的细节上有所差别。因此,有了环境变量解析的基础,对象解析只需要处理第二阶段,即依赖解析的流程即可

9. 项目信息

新增修改一览,新增(13),修改(5)。

beans
└─ src
   ├─ main
   │  └─ java
   │     └─ cn.stimd.spring.beans
   │        └─ factory
   │           ├─ annotation
   │           │  ├─ Autowired.java (+)
   │           │  ├─ AutowiredAnnotationBeanPostProcessor.java (+)
   │           │  ├─ InjectionMetadata.java (+)
   │           │  ├─ Qualifier.java (+)
   │           │  └─ Value.java (+)
   │           ├─ config
   │           │  ├─ AutowireCapableBeanFactory.java (*)
   │           │  ├─ BeanDefinitionHolder.java (+)
   │           │  ├─ BeanPostProcessor.java (+)
   │           │  ├─ ConfigurableBeanFactory.java (*)
   │           │  ├─ DependencyDescriptor.java (+)
   │           │  └─ InstantiationAwareBeanPostProcessor.java (+)
   │           └─ support
   │              ├─ AbstractAutowireCapableBeanFactory.java (*)
   │              ├─ AbstractBeanFactory.java (*)
   │              ├─ AutowireCandidateResolver.java (+)
   │              ├─ DefaultListableBeanFactory.java (*)
   │              └─ QualifierAnnotationAutowireCandidateResolver.java (+)
   └─ test
      └─ java
         └─ beans
            └─ autowire
               ├─ AutowireConfig.java (+)
               └─ AutowireTest.java (+)

注:+号表示新增、*表示修改

注:项目的 master 分支会跟随教程的进度不断更新,如果想查看某一节的代码,请选择对应小节的分支代码。


欢迎关注公众号【Java编程探微】

原创不易,觉得内容不错请分享一下。

转载自:https://juejin.cn/post/7374824876115165199
评论
请登录