1
头图

spring对象管理绕不开IOC,那什么是IOC?

IOC是一种思想——让业务对象A、B解耦,对象创建过程交由Spring维护;而这种思想的实现靠DI完成

这里给出两个概念的详细解释(个人理解)

IOC控制反转

举例,A依赖B——B是A的必要属性
过去:当运行到某功能时,如果B is null,A必须创建B或为其赋值才能保证功能的正常运行。即,控制权在A手中。
现在:IOC的理念是,控制权交给平台(或者叫框架,或者叫容器),无论是A、B都由Spring创建。控制权反转,已不再自己手中。

DI依赖注入

依然以此为例:A依赖B——B是A的必要属性
A的依赖B——这个属性的赋值靠Spring的注入(@Autowire)完成

道的部分打住,进入术的部分。

看看spring初始化过程如何实现IOC的。

一、核心方法refresh

// == 入口
public static void main(String[] args) {
    SpringApplication.run(SpringRunner.class, args);
}

// == 调用链
org.springframework.boot.SpringApplication#run(java.lang.Class<?>, java.lang.String...)
org.springframework.boot.SpringApplication#run(java.lang.Class<?>[], java.lang.String[])
org.springframework.boot.SpringApplication#run(java.lang.String...)
org.springframework.boot.SpringApplication#refreshContext
org.springframework.boot.SpringApplication#refresh

refresh方法就是核心方法;虽然找到它的过程十分草率,但不妨碍它非常重要

列出初始化相关代码:

// == 二、工厂创建
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();

// == 三、对象创建
finishBeanFactoryInitialization(beanFactory);

二、工厂创建obtainFreshBeanFactory

本节深入分析构建BeanFactory的过程。

ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

// == 调用链    
org.springframework.context.support.AbstractApplicationContext#obtainFreshBeanFactory
org.springframework.context.support.AbstractRefreshableApplicationContext#refreshBeanFactory
// -- 分析注解方式注入
org.springframework.web.context.support.AnnotationConfigWebApplicationContext#loadBeanDefinitions

1.向容器注册对象描述信息

注入的本质就是向容器(也有叫上下文的,Context的直译)——一个Map注册对象的描述信息

用代码描述就是:
beanDefinitionMap.put(BeanDefinition)

我们来看看具体实现:

// == 注册逻辑
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {
   AnnotatedBeanDefinitionReader reader = getAnnotatedBeanDefinitionReader(beanFactory);

   if (!this.annotatedClasses.isEmpty()) {
      reader.register(this.annotatedClasses.toArray(new Class<?>[this.annotatedClasses.size()]));
   }
}

// == 调用链
org.springframework.context.annotation.AnnotatedBeanDefinitionReader#register
org.springframework.context.annotation.AnnotatedBeanDefinitionReader#registerBean(java.lang.Class<?>)
org.springframework.context.annotation.AnnotatedBeanDefinitionReader#doRegisterBean

doRegisterBean这个方法值得细说一下:

<T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
            @Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {

    //## 被注解修饰的对象,会被封装成BeanDefinition结构
    AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);

    //为注解Bean定义生成Bean名称
    String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
    // BeanDefinition再次封装
    BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);

    // ## 注册
    BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}

// == 调用链
org.springframework.beans.factory.support.BeanDefinitionReaderUtils#registerBeanDefinition
// -- 前面创建的工厂是DefaultListableBeanFactory
org.springframework.beans.factory.support.DefaultListableBeanFactory#registerBeanDefinition

对象描述信息注册到哪里去了?

// 存储注册信息的BeanDefinition
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            throws BeanDefinitionStoreException {
    // ## 注册的的本质
    this.beanDefinitionMap.put(beanName, beanDefinition);
}

2.扫描指定的package配置信息

无它,只为扩大扫描范围
默认只注入SpringRunner(Starter类)的子包

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {  
   //为容器设置类路径Bean定义扫描器
   ClassPathBeanDefinitionScanner scanner = getClassPathBeanDefinitionScanner(beanFactory);

   if (!this.basePackages.isEmpty()) {
      scanner.scan(this.basePackages.toArray(new String[this.basePackages.size()]));
   }
}

// == 调用链
org.springframework.context.annotation.ClassPathBeanDefinitionScanner#scan
org.springframework.context.annotation.ClassPathBeanDefinitionScanner#doScan

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
    //遍历扫描所有给定的包
    for (String basePackage : basePackages) {
        // ## 同样执行注入流程
        registerBeanDefinition(definitionHolder, this.registry);
    }
}

三、对象创建finishBeanFactoryInitialization

依然从非常重要的refresh()方法入手。

// spring bean对象初始化在这里(非懒加载未知)
finishBeanFactoryInitialization(beanFactory);

// == 调用链
org.springframework.context.support.AbstractApplicationContext#finishBeanFactoryInitialization
org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons

public void preInstantiateSingletons() throws BeansException {
    for (String beanName : beanNames) {
        // 封装后的BeanDefinition,从beanDefinitionMap获取
        RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
        // 非懒加载的Bean
        if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
            // ## 初始化
            getBean(beanName);
        }
    }
}

getBean(beanName)是spring初始化对象的入口。

对象初始化getBean

一个常见的对象依赖举例:

@Component
class A {
    @Autowire
    B b;
}

@Component
class B{

}

化繁为简后,整个getBean()方法逻辑如下:

getBean(String name){
    // -- 1.增加标记【singletonsCurrentlyInCreation.set(beanName)】
    beforeSingletonCreation(beanName);
    
    // -- 2.构造函数创建对象【A对象创建了,它的属性b为空】
    instanceWrapper = createBeanInstance(beanName, mbd, args);
    
    // -- 3.属性初始化
    // 【初始化属性b开始】
    populateBean();
           ⬇⬇⬇⬇⬇
        递归调用getBean(String name)【初始化B对象完成】
           ⬆⬆⬆⬆⬆
    // 【初始化属性b结束】
    populateBean(); 
    
    // -- 4.调用对象后置处理器,返回代理对象(aop相关)
    initializeBean(beanName, exposedObject, mbd)
    
    // -- 5.对属性进行注入【A对象的b属性有值】
    applyPropertyValues(beanName, mbd, bw, pvs);        
    
    // -- 6.移除标记【singletonsCurrentlyInCreation.remove(beanName)】
    afterSingletonCreation(beanName);
    
    // -- 7.对象存入一级缓存【完结撒花,A对象初始化完成】
    addSingleton(beanName, singletonObject);
}

上述过程提到了一级缓存,以及标记集合

##### DefaultSingletonBeanRegistry类 ##### 
// 记录正在被创建的bean
private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap(16));
// 一级缓存,存放全部初始化完成的对象
private final Map<String, Object> singletonObjects = new ConcurrentHashMap(256);

如一些场景,需要手动从SpringContext获取Bean对象,实质就是从一级缓存中获取。

除了一级缓存,其实还存在二级、三级缓存。

// 二级缓存,存放早期对象(半成品对象,属性未赋值)
private final Map<String, Object> earlySingletonObjects = new HashMap(16);
// 三级缓存,存放对象工厂
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);

对象初始化过程似乎并未用到二级、三级缓存,它们的作用是什么?

二级、三级缓存用于解决“对象循环依赖问题”,这部分内容留在下篇分析。

附录

P6-P7知识合辑


青鱼
268 声望25 粉丝

山就在那里,每走一步就近一些