基本概念
「Spring是一个IOC容器」
当我们不用Spring进行开发时,我们需要在代码中设置对象的依赖关系。当我们用了Spring之后,由Spring来管理这种依赖关系,当我们想使用对象时,直接从Spring容器中获取即可
「BeanDefinition」
在Spring中对象被叫做Bean,因为Spring Bean在Java类的基础上增加了很多概念,比如scope(作用域),isLazyInit(是否延迟初始化),isSingleton(是否单例),此时Java类不能完整的描述,所以需要新的定义描述类,这个类就是BeanDefinition
「BeanDefinitionReader」
BeanDefinitionReader会将配置的bean解析成为BeanDefinition,Spring Bean的配置方式有很多种,如XML,properties,groovy,注解(可能通过properties,groovy的方式你不常用,但Spring确实支持这种方式),所以BeanDefinitionReader的实现类也很多
「ClassPathBeanDefinitionScanner」当把Bean配置出后,得需要相应的组件把他们从资源文件中扫描出来吗,这个组件就是ClassPathBeanDefinitionScanner
「BeanDefinitionRegistry」BeanDefinitionReader将配置的bean解析成为BeanDefinition,需要将BeanDefinition保存到BeanDefinitionRegistry。类似工厂把原料保存到仓库中,供后续生产产品使用
「BeanFactory」
BeanFactory会根据BeanDefinition将Bean生产出来,并保存下来
「DefaultListableBeanFactory」
DefaultListableBeanFactory在绝大多数的场景都是BeanFactory的实现类,DefaultListableBeanFactory实现了BeanDefinitionRegistry接口和BeanFactory接口,所以能保存Bean定义,同时又能根据Bean定义将Bean生产出来
「BeanPostProcessor」
BeanFactory根据BeanDefinition生成Bean的过程是一个标准化的流程,就像一个流水线一样,当然你可以在这个流水线上做一些自定义的操作。「在Spring中你可以通过实现BeanPostProcessor来干预Bean的生产过程」
「BeanFactoryPostProcessor」
Spring作为一个强大的容器,不仅能让你干预Bean的生产过程,还可以让你干预BeanFactory,「例如你可以通过BeanFactoryPostProcessor将Bean的作用域都该成原型,默认是单例」
Spring容器启动流程
容器初始化过程
我们常用的容器有如下2种
- 基于xml配置Bean(ClassPathXmlApplicationContext)
- 基于注解配置Bean(AnnotationConfigApplicationContext)
因为我们现在开发都是基于注解,所以分析一下AnnotationConfigApplicationContext的启动流程
@Repository
public class UserDao {
public String getUser() {
return "user";
}
}
@Configuration
@ComponentScan("com.javashitang")
public class AppConfig {
}
public class Main {
public static void main(String[] args) {
// 容器启动完毕
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
UserDao userDao = context.getBean(UserDao.class);
String str = userDao.getUser();
System.out.println(str);
}
}
可以看到当AnnotationConfigApplicationContext被new出来的时候,容器已经启动完毕,后续就可以直接从容器中获取Bean了。
构造函数主要执行了如下3个步骤,其中this和register方法主要是容器初始化的过程。refresh是刷新容器,即启动的过程,在这个里面做了很多操作,我们后面会用一个小节来分析
初始化的过程可以看到初始化beanFactory为DefaultListableBeanFactory。「这里可以看到AnnotationConfigApplicationContext虽然本身是一个beanFactory(实现了BeanFactory接口),但是依赖查找,依赖注入的过程是依赖内部的beanFactory来实现的(典型的代理模式)」
「另外需要注意的一点是,在容器初始化的过程中注册了6个Bean」
- ConfigurationClassPostProcessor(「实现了BeanFactoryPostProcessor,处理@Configuration,@ComponmentScan等注解,这是一个很重要的类」)
- 「AutowiredAnnotationBeanPostProcessor(实现了BeanPostProcessor,处理@Autowired,@Value等)」
- 「CommonAnnotationBeanPostProcessor(实现了BeanPostProcessor,用来处理JSR-250规范的注解,如@Resource,@PostConstruct等)」
- PersistenceAnnotationBeanPostProcessor(实现了BeanFactoryPostProcessor,用来支持JPA,在我们这个Demo中不会注册,因为路径中没有JPA相关的类)
- EventListenerMethodProcessor(实现了BeanFactoryPostProcessor)
- DefaultEventListenerFactory
注册的过程估计你也猜到了,就是将对应的类,如ConfigurationClassPostProcessor解析为RootBeanDefinition,并注册到BeanDefinitionRegistry中
「这几个BeanPostProcessor在Spring Bean的生命周期中发挥了很大的作用,我们在Spring Bean生命周期这篇文章中来分析」。
「好了,我们来看最重要的过程,容器刷新的过程,入口方法为AbstractApplicationContext#refresh」
容器刷新过程
「容器刷新的过程可以细分为如下几个步骤」
- Spring应用上下文启动准备阶段
- BeanFactory创建阶段
- BeanFactory准备阶段
- BeanFactory后置处理阶段
- BeanFactory注册BeanPostProcessor阶段
- 初始化内建Bean:MessageSource
- 初始化内建Bean:Spring事件广播器
- Spring应用上下文刷新阶段
- Spring事件监听器注册阶段
- BeanFactory初始化完成阶段
- Spring应用上下文启动完成阶段
Spring应用上下文启动准备阶段
AbstractApplicationContext#prepareRefresh
- 记录启动时间 startupDate
- 设置标志为closed(false),active(true)
- 初始化PropertySources
- 校验Environment中必须属性
- 初始化事件监听器集合
- 初始化早期Spring事件集合
BeanFactory创建阶段
AbstractApplicationContext#obtainFreshBeanFactory
刷新Spring应用上下文底层BeanFactory(refreshBeanFactory)
- 如果已存在BeanFactory,销毁Bean,并且关闭BeanFactory
- 创建DefaultListableBeanFactory(一般情况下都是DefaultListableBeanFactory)
- 设置BeanFactor