前言
对于Java开发者来说,使用最多的框架必然是spring了,而对于spring,我们常常都会说spring就是一个bean容器,帮我们管理bean;而这个容器的上层接口就是beanFactory;
BeanFactory定义了许多对bean的操作方法,比如通过名称获取bean,判断是否单例bean等
这一节来介绍下IOC容器的底层是啥样子的,以及简单梳理下spring启动流程
大纲
通过本文你将学到:
- spring常用的一些概念以及类,包括用途及关系
- Spring容器的启动流程源码
常用类及概念
因为IOC容器工厂相关的子类太多,我们先梳理下有哪些,具体的作用是什么,然后再方便介绍源码
BeanFactory基础容器
ListableBeanFactory: 表示这些 Bean 是可列表化的(会有多个bean),可以通过这个获取bean配置清单
HierarchicalBeanFactory: 表示的是这些 Bean 是有继承关系的,也就是每个 Bean 有可能有父 Bean
AutowireCapableBeanFactory: 定义 Bean 的自动装配规则(提供创建bean,自动注入,初始化以及应用bean的后处理器)
DefaultListableBeanFactory : 这是最终实现类(综合上述所有功能,主要是对bean注册后的处理)
上面是BeanFactory的一些实现类,BeanFactory可以认为是一个基础的容器接口,定义了一些简单的对bean的操作(获取对象、实例化对象等);下面介绍spring中更高级的容器ApplicationContext。
BeanFactory实操XmlBeanFactory(已过时)
BeanFactory的实现是懒加载的,即在使用时加载
public class HelloWorldApp {
public static void main(String[] args) {
XmlBeanFactory factory = new XmlBeanFactory (new ClassPathResource("beans.xml"));
HelloWorld obj = (HelloWorld) factory.getBean("helloWorld");
obj.getMessage();
}
}
他们之间的区别可以在网上看看别的文章:
BeanFactory vs ApplicationContext
ApplicationContext高级容器
ApplicationContext继承于BeanFactory,即实现了BeanFactory的所有功能,还有更多其他的功能 MessageSource:支持信息源,可以实现国际化
ResourcePatternResolver:访问资源,如URL和文件
ApplicationEventPublisher:支持应用事件,消息发送、响应机制
常用实现类:GenericApplicationContext,ClasspathXmlApplicationContext
DefaultSingletonBeanRegistry
这是单例bean注册器,实现了SingletonBeanRegistry;提供bean的获取、注册等功能;大名鼎鼎的三级缓存(SingletonFactories,earlySingletonObjects,singletonObjects)也是在这里面
DefaultSingletonBeanRegistry是spring的核心类
BeanDefinition
对于BeanDefinition,其实大家都很熟悉,就是bean的定义;在spring中,我们在xml中的配置,都是先转成beandefinition(存储在比如DefaultListableBeanFactory的hashmap中);然后再实例化成bean对象的(DefaultSingletonBeanRegistry中)
完成解析任务的类就是我们的BeanDefinitionReader
BeanFactoryPostProcessor & BeanPostProcessor
BeanFactoryPostProcessor经常用来修改bean定义,或者添加bean定义
定义:BeanFactoryPostProcessor的主体是BeanFactory,并且该接口中只定义了一个方法,其将会在ApplicationContext内部的BeanFactory加载完bean的定义后,但是在对应的bean实例化之前进行回调
核心方法:postProcessBeforeInitialization、postProcessAfterInitialization
BeanFactoryPostProcessor经常用来针对bean进行proxy
定义:BeanPostProcessor 该接口我们也叫后置处理器,作用是在Bean对象在实例化和依赖注入完毕后,在显示调用初始化方法的前后添加我们自己的逻辑。注意是Bean实例化完毕后及依赖注入完成后触发的
核心方法:postProcessBeanFactory
BeanFactoryPostProcessor还有个子接口BeanDefinitionRegistryPostProcessor,里面提供了postProcessBeanDefinitionRegistry方法,这个把BeanDefinitionRegistry暴露给我我们,可以用来注册beanDefinition等
spring容器启动流程
接下来,开始下重头戏-分析下spring容器的源码;根据前面介绍的,spring高级容器一定是ApplicationContext的一个子类,常用的有xml(ClassPathXmlApplicationContext),注解(AnnotationConfigApplicationContext),这里用AnnotationConfigApplicationContext来作为例子:
测试代码:
public class SpringIocContext {
public static void main(String[] args) {
// ApplicationContext app = new ClassPathXmlApplicationContext("application.xml");
AnnotationConfigApplicationContext annotationConfigApplicationContext =
new AnnotationConfigApplicationContext(Test.class);
}
}
构造方法
/**
* Create a new AnnotationConfigApplicationContext, deriving bean definitions
* from the given component classes and automatically refreshing the context.
* @param componentClasses one or more component classes — for example,
* {@link Configuration @Configuration} classes
*/
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
// 调用空构造方法
this();
// 将配置类的BeanDefinition注册到容器中
register(componentClasses);
// 调用refresh()方法刷新容器
refresh();
}
可以发现构造方法里面主要做了三件事:
- 初始化Spring容器,注册内置的BeanPostProcessor的BeanDefinition到容器中
- 将配置类的BeanDefinition注册到容器中
- 调用refresh()方法刷新容器
接下来,一步步分析这三件事。。
初始化Spring容器
构造方法初始化spring容器时主要做了三件事:
- 实例化beanFactory工厂(DefaultListableBeanFactory):这个在父类GenericApplicationContext中
- 实例化注解配置读取器BeanDefinitionReader(AnnotatedBeanDefinitionReader)
- 实例化路径扫描器ClassPathBeanDefinitionScanner,用于对指定的包目录进行扫描查找 bean 对象
对于第二步中,重点介绍下:org.springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors
这个方法主要是注册一些内置的组件到容器中,比如:
- ConfigurationClassPostProcessor: beanFactory 后置处理器,用来完成 bean 的扫描与注入工作;实现了BeanFactoryPostProcessor
- AutowiredAnnotationBeanPostProcessor: bean 后置处理器,用来完成 @AutoWired 自动注入,实现了BeanPostProcessor
- CommonAnnotationBeanPostProcessor、EventListenerMethodProcessor、DefaultEventListenerFactory等其他组件
注册SpringConfig配置类到容器中
这块主要是将我们前面调用容器构造方法时传入的bean解析成一个 BeanDefinition 然后注册到容器;核心逻辑在:org.springframework.context.annotation.AnnotatedBeanDefinitionReader#doRegisterBean
逻辑无非就是反射解析注解+对象,然后注册到容器;具体代码不多说
refresh()容器刷新流程
efresh刷新容器就是整体spring容器启动的核心流程,其中主要做的事有如下几个:
prepareRefresh
刷新前的预处理
obtainFreshBeanFactory();
获取 beanFactory,即前面创建的【DefaultListableBeanFactory】
1.刷新beanFactory并设置序列化id
2.返回前面创建的BeanFactory
prepareBeanFactory
预处理 beanFactory,向容器中添加一些组件,代码具体对于以下:
- 设置 bean 表达式解析器
- 添加一个 BeanPostProcessor【ApplicationContextAwareProcessor】
- 设置某些bean不能通过自动装配注入(即不能使用注解直接使用)
- 设置注册某些bean可以通过自动装配注入
- 添加一个 BeanPostProcessor【ApplicationListenerDetector】
- 添加编译时的 AspectJ
- 注册 environment 组件、systemProperties 组件、systemEnvironment 组件
postProcessBeanFactory
子类通过重写这个方法可以在 BeanFactory 创建并与准备完成以后做进一步的设置
invokeBeanFactoryPostProcessors
执行 BeanFactoryPostProcessor 方法,beanFactory 后置处理器;
这一段代码很多,但整体逻辑就是执行postProcessBeanDefinitionRegistry()方法、postProcessBeanFactory() 方法;并且按照PriorityOrdered、Ordered的顺序去执行
registerBeanPostProcessors
向容器中注入BeanPostProcessor;(仅仅注入而非使用),在后续spring创建、初始化bean时会用到,包括代理、自动注入、循环依赖等
initApplicationEventMulticaster
初始化事件派发器,在注册监听器时会用到(用来承载监听器)
主要是往beanFactory注册一个事件派发器(ApplicationEventMulticaster),默认是SimpleApplicationEventMulticaster,有自定义就用自定义的
registerListeners
扫描ApplicationListener,并将其添加到派发器中ApplicationEventMulticaster;
主要是将之前步骤初始化的,和容器中所有自定义的加入派发器中
finishBeanFactoryInitialization
实例化所有非懒加载的bean,具体逻辑在这个方法中;比较复杂,后续单独讲解
org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons
finishRefresh
容器初始化完成后,后续的扫尾工作;
包括清理缓存,初始化生命周期处理器,发布容器刷新事件等。
后续
后续详细介绍下springBean的生命周期