Spring启动过程中的一些关键点

依赖注入发生的时间

当Spring IoC容器完成了所有Bean定义的定位、载入、解析和注册以后,IoC容器中已经包含了Bean定义相关的数据,但是此时IoC容器还没有对所管理的Bean进行依赖注入,依赖注入在以下两种情况发生:

  1. 用户第一次通过getBean方法向IoC容索要Bean时,IoC容器触发依赖注入。
  2. 当用户在Bean定义关闭了懒加载lazy-init=false(默认是关闭的); 容器在解析注册Bean定义时进行预实例化,触发依赖注入。

ctx.getBean解析

AbstractApplicationContext::getBean

会委托bean工厂来getBean, 而这个Bean工厂的实现就是DefaultListableBeanFactory

1
2
3
4
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
...
return getBeanFactory().getBean(name, requiredType);
}

AbstractBeanFactory::getBean

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
return doGetBean(name, requiredType, null, false);
}

protected <T> T doGetBean(
final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
throws BeansException {

...
// 先从缓存中获取bean
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
...
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);

// 初始化依赖的bean
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
registerDependentBean(dep, beanName);
getBean(dep); // 递归调用getBean ---------------------
}
}

// 单例模式下
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
...
return createBean(beanName, mbd, args); // 本类的createBean是抽象方法, 依赖子类来实现
...
}
});
//获取给定Bean的实例对象
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}

// 原型模式, 直接创建一个新的bean
else if (mbd.isPrototype()) {
...
Object prototypeInstance = null;
prototypeInstance = createBean(beanName, mbd, args);
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
...
}

//
else {
...
/*
要创建的Bean既不是单态模式,也不是原型模式,则根据Bean定义资源中
配置的生命周期范围,选择实例化Bean的合适方法,这种在Web应用程序中
比较常用,如:request、session、application等生命周期
*/

}
...
}

//对创建的Bean实例对象进行类型检查
...

return (T) bean;
}
  • 如果Bean定义的单态模式(Singleton),则容器在创建之前先从缓存中查找,以确保整个容器中只存在一个实例对象。
  • 如果Bean定义的是原型模式(Prototype),则容器每次都会创建一个新的实例对象。
  • 除此之外,Bean定义还可以扩展为指定其生命周期范围。
    上面的源码只是定义了根据Bean定义的模式,采取的不同创建Bean实例对象的策略,具体的Bean实例对象的创建由匿名内部类中通过调用外部方法createBean方法完成,ObejctFactory使用委派模式,具体的createBean过程交由其实现类AbstractAutowireCapableBeanFactory完:

    AbstractAutowireCapableBeanFactory::createBean

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
    ...
    // 创建Bean的入口
    Object beanInstance = doCreateBean(beanName, mbdToUse, args);
    ...
    }

    //真正创建Bean的方法
    protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
    throws BeanCreationException {
    ...
    // 如果缓存中没有, 则 (1) 生成Bean所包含的java对象实例
    instanceWrapper = createBeanInstance(beanName, mbd, args);
    final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
    ...
    Object exposedObject = bean;
    // (2) 对Bean属性的依赖注入进行处理
    populateBean(beanName, mbd, instanceWrapper);
    ...
    // 初始化Bean对象
    exposedObject = initializeBean(beanName, exposedObject, mbd);
    ...
    return exposedObject;
    }

通过对方法源码的分析,我们看到具体的依赖注入实现在以下两个方法中:

  • createBeanInstance:生成Bean所包含的java对象实例。
  • populateBean :对Bean属性的依赖注入进行处理。

总结

  1. 在getBean后, 先实例化要get的Bean (假设当前所有的Bean都尚未实例化)
  2. 对该Bean的属性进行注入, 再实例化属性中需要引用的Bean
  3. 如果是有参构造, 则先实例化参数的bean
  4. dependsOn的Bean会在该Bean之前被实例化, 需要在bean定义的时候指定depends-on属性( 不常用, 一般都是通过构造参数, 或者属性来确定依赖关系 )

AbstractAutowireCapableBeanFactory::createBeanInstance

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
// 有参构造器, 等情况
if (ctors != null ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
return autowireConstructor(beanName, mbd, ctors, args);
}
...
// 无参构造器, 实例化Bean
return instantiateBean(beanName, mbd);
}

protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
...
//
beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
...
BeanWrapper bw = new BeanWrapperImpl(beanInstance);
initBeanWrapper(bw);
return bw;
---
}

默认无参构造方法就需要使用相应的初始化策略 (JDK的反射机制或者CGLIB) 来进行初始化了,在方法getInstantiationStrategy().instantiate中就具体实现类使用初始策略(SimpleInstantiationStrategy)实例化对象。

SimpleInstantiationStrategy::instantiate

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner) {
...
final Class<?> clazz = bd.getBeanClass();
...
constructorToUse = clazz.getDeclaredConstructor((Class[]) null);
...
//如果Bean定义中没有方法覆盖,则通过JDK床架对象
if (beanDefinition.getMethodOverrides().isEmpty()) {
// 通过反射创建对像
return BeanUtils.instantiateClass(constructorToUse);
...
}
else{
// 通过CGLIB创建对象
return instantiateWithMethodInjection(beanDefinition, beanName, owner);
}

}

AbstractAutowireCapableBeanFactory::populateBean

对属性的注入过程分以下两种情况:

  1. 属性值类型不需要转换时,不需要解析属性值,直接准备进行依赖注入。
  2. 属性值需要进行类型转换时,如对其他对象的引用等,首先需要解析属性值,然后对解析后的属性值进行依赖注入。
    对属性值的解析是在BeanDefinitionValueResolver类中的resolveValueIfNecessary方法中进行的,对属性值的依赖注入是通过bw.setPropertyValues方法实现的.

其他特性

  • BeanPostProcessor后置处理器的实现:
    BeanPostProcessor后置处理器是Spring IoC容器经常使用到的一个特性,这个Bean后置处理器是一个监听器,可以监听容器触发的Bean声明周期事件。后置处理器向容器注册以后,容器中管理的Bean就具备了接收IoC容器事件回调的能力。
    BeanPostProcessor的使用非常简单,只需要提供一个实现接口BeanPostProcessor的实现类,然后在Bean的配置文件中设置即可。
0%