Spring IOC容器的加载过程
1、实例化容器:AnnotationConfigApplicationContext
首先从这里出发:
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
创建 AnnotationConfigApplicationContext对象实例化bean工厂,走的是无参构造方法,而无参构造方法又会去调用父类的无参构造方法。为什么这里要实现的是DefaultListableBeanFactory()?因为这个类继承了最多的父类,包括BeanDefinitionRegistry,功能是最丰富的,比如注册bean定义的方法。所以实现了这个DefaultListableBeanFactory()后赋值给beanFactory,得到了bean工厂
//根据参数类型可以知道,其实可以传入多个annotatedClasses,但是这种情况出现的比较少
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
//调用无参构造函数,会先调用父类GenericApplicationContext的构造函数
//父类的构造函数里面就是初始化DefaultListableBeanFactory,并且赋值给beanFactory
//本类的构造函数里面,初始化了一个读取器:AnnotatedBeanDefinitionReader read,一个扫描器ClassPathBeanDefi
nitionScanner scanner
//scanner的用处不是很大,它仅仅是在我们外部手动调用 .scan 等方法才有用,常规方式是不会用到scanner对象的
this();
//把传入的类进行注册,这里有两个情况,
//传入传统的配置类
//传入bean(虽然一般没有人会这么做
//看到后面会知道spring把传统的带上@Configuration的配置类称之为FULL配置类,不带@Configuration的称之为Lite配
置类
//但是我们这里先把带上@Configuration的配置类称之为传统配置类,不带的称之为普通bean
register(annotatedClasses);
//刷新
refresh();
}
//this()执行的无参构造方法
public AnnotationConfigApplicationContext() {
/**
* 初始化注解模式下的bean定义扫描器
* 调用AnnotatedBeanDefinitionReader构造方法,传入的是this(AnnotationConfigApplicationContext)对象
*/
this.reader = new AnnotatedBeanDefinitionReader(this);
/**
* 初始化我们的classPath类型的bean定义扫描器
*/
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
//父类具体执行的构造方法
public GenericApplicationContext() {
/**
* 调用父类的构造函数,为ApplicationContext spring上下文对象初始beanFactory
* 为啥是DefaultListableBeanFactory?我们去看BeanFactory接口的时候
* 发DefaultListableBeanFactory是最底层的实现,功能是最全的
*/
this.beanFactory = new DefaultListableBeanFactory();
}
接下来会去执行new AnnotatedBeanDefinitionReader(this)(创建用去读取配置类的工具。);在执行这一句的时候会去注册一些创世纪的类例的bean定义如ConfigurationClassPostProcessor.class(在这个类中负责解析配置类,会解析加了@Configuration\@Component\@Import等注解)、AutowiredAnnotationBeanPostProcessor.class(这个类会去解析@Autowired)等处理器,这个只是注册这些类,真正去把类解析bean定义的是由他注册的后置处理器去完成的。
接下来会去执行this.scanner = new ClassPathBeanDefinitionScanner(this);创建扫面读取到的配置类的工具。在这个扫描工具里面有个doScan(String basePackages)方法,提供一个手动传入扫描包进行扫描的支持。传入一个包路径,通过这个路径扫描到包里面的所有类。
在构造方法跳出来之后会执行注册配置类到bean定义里面
接着会执行refresh()方法
refresh()方法
invokeBeanFactoryPostProcessors(beanFactory);
调用我们的bean工厂的后置处理器。因为之前已经注册了创世纪类ConfigurationClassPostProcessor.class,所以这里执行getBean()就会实例化注册了的创世纪的类(实现了postprocessor接口),这里调用这些实例化了的处理器就会去解析配置类、@CompenetScan、@Import等注解注册到bean定义里面。
registerBeanPostProcessors(beanFactory);
注册bean的后置处理器
finishBeanFactoryInitialization(beanFactory);
实例化剩余的单例bean。
在这里面会执行getBean(),判断需要实例化的这个Bean定义是否符合生产标准、是不是factorybean。符合标准了才会执行getBean()。这时候会先去判断一级缓存是否有,如果拿到了直接返回,如果没有拿到就会标记为isInCreation正在创建,去执行creatBean()。
creatBean()中会执行第一个bean后置处理器,这里可以阻止bean的创建交由用户自己创建。
接着就来到了doCreatBean(),进行实例化、填充属性、初始化,最终把bean放入一级缓存。
springBean生命周期
阶段1:处理名字,检查缓存,因为spring是支持别名系统,也就是一个bean可以起一个小名,将来根据小名也能找到这个bean,所以在这一步是将这个别名翻译成真正的名字。是为了实现单例bean,检查缓存单例池中是否已经存在,如果有就直接拿不再创建。
阶段2:检查父工厂,针对的是beanFactory有一个父子继承关系,如果子工厂没有这个Bean就会去父工厂中走getBean
阶段3:检查bean的dependsOn,应该先创建dependon的bean,保证先后顺序
阶段4:按Scope创建bean
- 创建singleton
- 创建prototype:多例bean
- 创建其他scope
阶段5:
- 创建bean实例
- 依赖注入
- 初始化:调用各种初始化方法。
- 登记可销毁bean
阶段6:类型转换:根据requiredType进行类型转换。
阶段7:销毁阶段5登记的可销毁bean