追踪解析Spring ioc启动源码(1)

零 前期准备

0 FBI WARNING

文章异常啰嗦且绕弯。

1 版本

spring版本 : spring 5.1.2.RELEASE

IDE : idea 2018.3

2 Bean Demo

package ioc;

/**
 * java bean
 */
public class Person {

    private String name;
    private Integer age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}

3 Config Demo

package ioc;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 配置类
 */
@Configuration
public class IocConfig {

    /**
        * 用代码配置方式注入一个bean
        */
    @Bean(name = "person")
    public Person getPerson(){
        Person person = new Person();
        person.setAge(100);
        person.setName("张三");
        return person;
    }
}

4 main方法

package ioc;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class IocTest {

    public static void main(String[] args){
        ApplicationContext context = new AnnotationConfigApplicationContext(IocConfig.class);
        Person person = (Person) context.getBean("person");
        System.out.println(person.getName() + " , " + person.getAge());
    }
}

一 项目的启动和Bean的注入

1 总览

Spring 的初始化被封装在这行代码中:

ApplicationContext context = new AnnotationConfigApplicationContext(IocConfig.class);

这个构造器方法内部有三行代码:

public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
    this();                            // 2 无参构造器
    register(annotatedClasses);        // 3 reader 注册配置类
    refresh();                        // 4 在 bean factory 中创造 bean
}

2 无参构造器

该 part 的起点为 AnnotationConfigApplicationContext 调用自身的无参构造器:

//AnnotationConfigApplicationContext.class
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
    this();                            // 2 无参构造器
    register(annotatedClasses);
    refresh();
}

追踪无参构造器:

//AnnotationConfigApplicationContext.class
public AnnotationConfigApplicationContext() {
    this.reader = new AnnotatedBeanDefinitionReader(this); //2.1
    this.scanner = new ClassPathBeanDefinitionScanner(this); //2.5
}

AnnotatedBeanDefinitionReader 创建的过程中会将 Spring 自身需要的 bean 和配置用的 bean 注册到 bean factory 中。

【ClassPathBeanDefinitionScanner 本例中暂时用不到,不做详细分析,只简单看一下构造方法】

AnnotationConfigApplicationContext 的父类 GenericApplicationContext 会在无参构造器中创建一个 DefaultListableBeanFactory ,也就是本例中的 bean factory:

//GenericApplicationContext.class
public GenericApplicationContext() {
    this.beanFactory = new DefaultListableBeanFactory();
}

DefaultListableBeanFactory 内部会维护了多个 ConcurrentHashMap 对象,用于分门别类地保存 bean。

最主要的一个 map 对象是 singletonObjects。这个对象被定义在 DefaultSingletonBeanRegistry 中,用于存放所有的单例 bean:

//DefaultSingletonBeanRegistry.class
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

2.1

AnnotatedBeanDefinitionReader 创建的过程中将 spring 需要的几个 processor bean 注册到 DefaultListableBeanFactory 中。主要过程为:

//AnnotatedBeanDefinitionReader.class
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
    //调用自身的另一个有参构造器
    //此处的 registry 即为 AnnotationConfigApplicationContext 本身
    //此处的 getOrCreateEnvironment(registry) 最终返回一个调用 StandardEnvironment 无参构造器创建出来的对象
    this(registry, getOrCreateEnvironment(registry));
}

//AnnotatedBeanDefinitionReader.class
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
    //参数非空效验
    Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
    Assert.notNull(environment, "Environment must not be null");
    
    //保存 AnnotationConfigApplicationContext
    this.registry = registry;
    //创建一个用于注解解析器,后面会用到
    this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);

    //注册 Spring 需要用到的 processor bean
    AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}

Environment 顾名思义,即为 Spring 所处的环境,包括 properties 配置的读取等。本例中暂时没有用到,按下不表。

上述代码的核心是调用 AnnotationConfigUtils 的 registerAnnotationConfigProcessors(…) 方法,继续追踪:

//AnnotationConfigUtils.class
public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
    registerAnnotationConfigProcessors(registry, null);
}

//AnnotationConfigUtils.class
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
        BeanDefinitionRegistry registry, @Nullable Object source) {

    //获取 bean factory
    DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
    
    //以下代码设置了 beanFactory 的两个内部对象,暂时不展开
    if (beanFactory != null) {
        if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
            beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
        }
        if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
            beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
        }
    }

    //新建一个集合,用于在方法末尾返回所有注册的 bean 的包装类,但是实际上本例中没有接收返回值,所以可以忽略
    Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);

    //判断 bean factory 中是否存在这个名称的 bean,如果不存在就注册一个,以下雷同
    if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
        //将要注册的 processor class 包装成一个 BeanDefinition
        RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
        //本例中 source 为 null
        def.setSource(source);
        //注册 bean,并添加到集合中
        beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
    }

    if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
        RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
        def.setSource(source);
        beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
    }

    //jsr250Present 与 jpaPresent 均为 boolean 类型的变量
    //jsr250Present 的意思是检查是否对 JSR-250 标准进行支持,jpaPresent 的意思是检查是否对 JPA 标准进行支持
    //目前 Spring 支持 JSR-250 标准,不支持 JPA 标准
    if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
        RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
        def.setSource(source);
        beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
    }

    if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
        RootBeanDefinition def = new RootBeanDefinition();
        try {
            def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
                    AnnotationConfigUtils.class.getClassLoader()));
        }catch (ClassNotFoundException ex) {
            throw new IllegalStateException(
                    "Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
        }
        def.setSource(source);
        beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
    }

    if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
        RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
        def.setSource(source);
        beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
    }

    if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
        RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
        def.setSource(source);
        beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
    }

    //返回上述的集合
    return beanDefs;
}

该方法中主体代码都是雷同的,即为:

if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
    //将要注册的 processor class 包装成一个 BeanDefinition
    RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
    //本例中 source 为 null
    def.setSource(source);
    //注册 bean ,并添加到集合中
    beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
}
CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME : org.springframework.context.annotation.internalConfigurationAnnotationProcessor
CONFIGURATION_BEAN_NAME_GENERATOR : org.springframework.context.annotation.internalConfigurationBeanNameGenerator
AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME : org.springframework.context.annotation.internalAutowiredAnnotationProcessor
COMMON_ANNOTATION_PROCESSOR_BEAN_NAME : org.springframework.context.annotation.internalCommonAnnotationProcessor
PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME : org.springframework.context.annotation.internalPersistenceAnnotationProcessor
PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME : org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor
EVENT_LISTENER_PROCESSOR_BEAN_NAME : org.springframework.context.event.internalEventListenerProcessor
EVENT_LISTENER_FACTORY_BEAN_NAME : org.springframework.context.event.internalEventListenerFactory

这些常量都是 spring 中类的路径和名称。

registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)

此行代码会通过 AnnotationConfigApplicationContext 调用到 DefaultListableBeanFactory 内部的 beanDefinitionMap 对象,最终查询到这个 bean 对象是否已经被注册。如果不存在,则执行下方的注册操作。

beanDefinitionMap 是 DefaultListableBeanFactory 内部存放所有已经注册了的 bean 的信息的 ConcurrentHashMap 对象,后面会经常提到。

RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);

RootBeanDefinition 是 BeanDefinition 的实现类。BeanDefinition 是 Spring 中 bean 的描述包装接口,用于保存 bean 的各类信息,包括且不限于 bean 的名称、父类、注解、是否惰性加载等属性。

Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);

BeanDefinitionHolder 是 BeanDefinition 的支持类,内部存储了 BeanDefinition 、bean name 、bean aliases(别名)。

【在 Spring 的 bean 注册过程中,有多次 BeanDefinition 和 BeanDefinitionHolder 的包装和解包装操作,具体有待学习】

registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)

起主要作用的是上面这行代码。追踪这个方法的实现:

//AnnotationConfigUtils.class
private static BeanDefinitionHolder registerPostProcessor(
            BeanDefinitionRegistry registry, RootBeanDefinition definition, String beanName) {

    //bean 的角色定义
    //BeanDefinition.ROLE_INFRASTRUCTURE = 2
    definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);

    //调用 AnnotationConfigApplicationContext 的 registerBeanDefinition 方法
    registry.registerBeanDefinition(beanName, definition);

    //返回一个封装类
    return new BeanDefinitionHolder(definition, beanName);
}

BeanDefinition 的 role 是指该 bean 在 Spring 中的角色定义。对于 Spring 注册进去的 processor bean,定义值均为 2,意思是 infrastructure(基础设施)。

除此以外角色定义还有 application(应用) 和 support(支持)。

AnnotationConfigApplicationContext 内部其实没有 registerBeanDefinition(…) 这个方法,而是继承自 GenericApplicationContext:

//GenericApplicationContext.class
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            throws BeanDefinitionStoreException {
    //2.2
    this.beanFactory.registerBeanDefinition(beanName, beanDefinition);
}

此方法实际上调用了 DefaultListableBeanFactory 的 registerBeanDefinition(…) 方法进行 bean 的注册。

2.2

继续追踪方法的内部实现:

//DefaultListableBeanFactory.class
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
        throws BeanDefinitionStoreException {

    //参数非空验证
    Assert.hasText(beanName, "Bean name must not be empty");
    Assert.notNull(beanDefinition, "BeanDefinition must not be null");

    //bean 的有效性验证
    if (beanDefinition instanceof AbstractBeanDefinition) {
        try {
            ((AbstractBeanDefinition) beanDefinition).validate();
        }
        catch (BeanDefinitionValidationException ex) {
            throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                    "Validation of bean definition failed", ex);
        }
    }

    //beanDefinitionMap 为存储所有注册 bean 信息的 map 对象
    //正常情况下此处获取的应该是 null 值,即该 bean 的信息还未注册
    BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);

    if (existingDefinition != null) {

        //如果 bean 已经存在于 map 中,则需要判断是否允许重写 bean definition
        if (!isAllowBeanDefinitionOverriding()) { //不允许,抛出异常
            throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
        }else if (existingDefinition.getRole() < beanDefinition.getRole()) {
            if (logger.isInfoEnabled()) {
                logger.info("Overriding user-defined bean definition for bean '" + beanName +
                        "' with a framework-generated bean definition: replacing [" +
                        existingDefinition + "] with [" + beanDefinition + "]");
            }
        }else if (!beanDefinition.equals(existingDefinition)) {
            if (logger.isDebugEnabled()) {
                logger.debug("Overriding bean definition for bean '" + beanName +
                        "' with a different definition: replacing [" + existingDefinition +
                        "] with [" + beanDefinition + "]");
            }
        }else {
            if (logger.isTraceEnabled()) {
                logger.trace("Overriding bean definition for bean '" + beanName +
                        "' with an equivalent definition: replacing [" + existingDefinition +
                        "] with [" + beanDefinition + "]");
            }
        }
        //只要设置为允许重写,就会在最后更新 map,只是记录的 log 内容会不同
        this.beanDefinitionMap.put(beanName, beanDefinition);
    }else { //正常情况下
        if (hasBeanCreationStarted()) { //2.3
            synchronized (this.beanDefinitionMap) {
                this.beanDefinitionMap.put(beanName, beanDefinition);
                List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
                updatedDefinitions.addAll(this.beanDefinitionNames);
                updatedDefinitions.add(beanName);
                this.beanDefinitionNames = updatedDefinitions;
                if (this.manualSingletonNames.contains(beanName)) {
                    Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
                    updatedSingletons.remove(beanName);
                    this.manualSingletonNames = updatedSingletons;
                }
            }
        }else {
            //将 bean 注册入 beanDefinitionMap 中
            this.beanDefinitionMap.put(beanName, beanDefinition);
            //将 bean name 添加入 beanDefinitionNames 中
            this.beanDefinitionNames.add(beanName);
            //将 bean name 从 manualSingletonNames 中删除
            this.manualSingletonNames.remove(beanName);
        }
        //清空数组
        this.frozenBeanDefinitionNames = null;
    }

    //2.4
    if (existingDefinition != null || containsSingleton(beanName)) {
        resetBeanDefinition(beanName);
    }
}

先来关注这行代码:

((AbstractBeanDefinition) beanDefinition).validate();

追踪一下这行代码:

//AbstractBeanDefinition.class
public void validate() throws BeanDefinitionValidationException {
    if (hasMethodOverrides() && getFactoryMethodName() != null) {
        throw new BeanDefinitionValidationException(
                "Cannot combine static factory method with method overrides: " +
                "the static factory method must create the instance");
    }

    if (hasBeanClass()) {
        //此方法内部也主要用到了 hasMethodOverrides() ,这里暂时忽略该方法
        prepareMethodOverrides();
    }
}

这个方法内部使用了 AbstractBeanDefinition 内定义的 hasMethodOverrides() 和 getFactoryMethodName() 方法去判断 beanDefinition 是否有效。同时满足这两个条件则会抛出异常。

根据官方文档的描述,hasMethodOverrides() 为如果 bean factory 重写了 bean 内的方法,就会返回 true;getFactoryMethodName() 为如果存在工厂方法就会返回该方法的名称。

【没有特别理解这几个方法的应用场景,根据网上资料来看,应该和 bean 的反射创建有一些关系】

再来关注这行代码:

this.frozenBeanDefinitionNames = null;

frozenBeanDefinitionNames 是定义在 DefaultListableBeanFactory 中的一个字符串数组,Spring 在完成 bean 注册之后会将 beanDefinitionNames 转成一个数组,并赋值给 frozenBeanDefinitionNames。

【此为 Spring 的一个内存优化操作】

2.3

看一下上述方法的片段:

if (hasBeanCreationStarted()) {
    synchronized (this.beanDefinitionMap) { //线程锁

        //执行注册操作
        this.beanDefinitionMap.put(beanName, beanDefinition);

        //用一个新的 list 去替换原来的
        List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
        updatedDefinitions.addAll(this.beanDefinitionNames);
        updatedDefinitions.add(beanName);
        this.beanDefinitionNames = updatedDefinitions;

        //检查单例 bean 名称集合
        if (this.manualSingletonNames.contains(beanName)) {
            Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
            updatedSingletons.remove(beanName);
            this.manualSingletonNames = updatedSingletons;
        }
    }
}

先来追踪一下 hasBeanCreationStarted() 这个方法的内部实现:

//AbstractBeanFactory.class
protected boolean hasBeanCreationStarted() {
    return !this.alreadyCreated.isEmpty();
}

alreadyCreated 是一个定义在 AbstractBeanFactory 中的集合,用于存放所有已经被创建(不是注册,是创建)的 bean 的名字。在创建和获取 bean 的时候都会去检查该集合。

在 processors bean 和 iocConfig bean 的注册阶段,该集合为空,此方法返回 false。但是要注意,在 person bean 的注册阶段,此时 iocConfig bean 已经被创建出来了,所以此集合是非空的,此方法返回 true。

//创建新列表
List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
//老列表被整个添加到新列表中
updatedDefinitions.addAll(this.beanDefinitionNames);
//添加 beanName 到新列表中
updatedDefinitions.add(beanName);
//替换
this.beanDefinitionNames = updatedDefinitions;

beanDefinitionNames 是一个定义在 DefaultListableBeanFactory 中的列表,用来存放所有注册的 bean 的名字。

if (this.manualSingletonNames.contains(beanName)) {
    //新建一个集合,并且将 manualSingletonNames 集合放入新集合中
    Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
    //删除这个 bean name
    updatedSingletons.remove(beanName);
    //替换
    this.manualSingletonNames = updatedSingletons;
}

manualSingletonNames 是一个定义在 DefaultListableBeanFactory 中的集合,用来存放已经被创建的单例 bean 的名字。因为是单例的,所以不允许重名 bean 的存在,这可能也是 Spring 这里使用集合的原因。

【Spring 的对于内存的优化精确到了每一个列表和集合的容量大小】

进入这个 if 判断条件的情况下,必然是这个 bean 还没有被创建,所以如果这个 bean 已经被放在在这个集合里,就需要删除。正常情况下 bean 的注册过程应该都不会进入执行这个代码片段。

2.4

看一下上述方法的片段:

if (existingDefinition != null || containsSingleton(beanName)) {
    resetBeanDefinition(beanName);
}

判断条件中的 existingDefinition 是上方定义的一个 BeanDefinition :

BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);

一般来说等于 null。

而 containsSingleton(…) 方法具体的实现是在 DefaultSingletonBeanRegistry 中:

//DefaultSingletonBeanRegistry.class
public boolean containsSingleton(String beanName) {
    return this.singletonObjects.containsKey(beanName);
}

上面文章中提到过,singletonObjects 是最终保存单例 bean 的 map 对象。

综合来看就是此判断条件可以理解为:如果该 bean 已经注册或者已经被创建,则返回 true,若均未则返回 false。所以一般正常的注册流程是不会执行 resetBeanDefinition(…) 方法的。

关于 resetBeanDefinition(…) 方法,不展开讲了,大致来说就是此方法内部会重新去创建该 bean。

到此为止,reader 已经创建完毕,并且 Spring 使用到的 processors 也已经注册完毕。DefaultListableBeanFactory.registerBeanDefinition 方法非常重要,后面 config bean 和 person bean 的注册也是使用这个方法。

2.5

回到原点:

//AnnotationConfigApplicationContext.class
public AnnotationConfigApplicationContext() {
    this.reader = new AnnotatedBeanDefinitionReader(this);
    this.scanner = new ClassPathBeanDefinitionScanner(this); //2.4
}

本例中暂时没有用到 ClassPathBeanDefinitionScanner,因为没有扫描包路径的方式去获取 bean。所以此处略讲一下 ClassPathBeanDefinitionScanner 的创建。

其构造方法有多层调用,最终的逻辑代码如下:

//ClassPathBeanDefinitionScanner.class
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
            Environment environment, @Nullable ResourceLoader resourceLoader) {
    //参数非空效验
    Assert.notNull(registry, "BeanDefinitionRegistry must not be null");

    //此处的 registry 是 AnnotationConfigApplicationContext
    this.registry = registry;

    //Spring 扫描包路径的过滤策略
    //useDefaultFilters = true
    if (useDefaultFilters) {
        registerDefaultFilters();
    }
    //存入环境对象,此处一个使用无参构造器创建出来的 StandardEnvironment 对象
    setEnvironment(environment);
    //存入 resourceLoader,此处为 AnnotationConfigApplicationContext
    setResourceLoader(resourceLoader);
}

【暂时不展开了】

To Be Continued …

    原文作者:三流
    原文地址: https://segmentfault.com/a/1190000017312620
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞