一、IOC的加载流程如下:

1、生活中的例子

如我们要购买一个衣柜(Bean),我们会先想好颜色款式(@Lazy@Scope)等,并找到衣柜店(ApplicationContext)进行购买,衣柜店可以自己生产(继承了BeanFactory),也可以请设计师(BeanDefinitionRegistry)根据我们的要求设计好图纸(BeanDefinition)给厂家(BeanFactory)进行生产
11.png

2、下面我们创建一个简单的工程,然后从源码去验证我们上面这个图所分析的加载过程是否正确

2.1加载Bean一般常用的有两种方法

a.xml(读取Bean定义是直接耦合的方式读取)
b.配置类(利用BeatFactoryPostProcessor进行解耦了,设计理念更先进)
所以我们下面就通过配置类加注解的方式来实验一下IOC的加载过程

  1. @ComponentScan("com.bean.test.bean")
  2. public class BeanConfig {
  3. }
  1. @Service
  2. public class User {
  3. public void sayHi(){
  4. System.out.println("hi");
  5. }
  6. }
  1. import com.bean.test.bean.User;
  2. import org.springframework.context.ApplicationContext;
  3. import org.springframework.context.annotation.AnnotationConfigApplicationContext;
  4. import org.springframework.context.annotation.ComponentScan;
  5. public class BeanApplication {
  6. public static void main(String[] args) {
  7. ApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig.class);
  8. User user = context.getBean(User.class);
  9. user.sayHi();
  10. }
  11. }

2.2工程运行正常打印hi的话说明工程就正常了

下面开始一步步的跟着源代码看加载过程了

2.2.1 查看AnnotationConfigApplicationContext的构造类

image.png
上图,我们在调用new AnnotationConfigApplicationContext(BeanConfig.class)的时候,
构造函数会调用this()的无参构造函数,无参构造函数如下:
image.png

2.2.2 查看AnnotationConfigApplicationContext的父类GenericApplicationContext的无参构造函数

image.png
可以看到,在创建AnnotationConfigApplicationContext对象的时候是会先new一个beanFactory出来,
DefaultListableBeanFactory继承自各种BeanFactory,拥有最全的功能,还实现了BeanDefinitionRegistry(Bean定义注册)功能
image.png

2.2.3 在无参构造函数中实现了配置读取类、配置扫描类

image.png

2.2.4 在new AnnotatedBeanDefinitionReader的时候还注册了一此处理器用以支撑ApplicationContext后面的运行

image.png
如ConfigurationClassPostProcessor处理器,用于解析我们的配置
image.png

2.2.5 注册我们的Bean配置类

image.png
image.png
image.png

2.2.6 refresh

image.png

  1. @Override
  2. public void refresh() throws BeansException, IllegalStateException {
  3. synchronized (this.startupShutdownMonitor) {
  4. StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
  5. // 1.准备刷新上下文环境
  6. prepareRefresh();
  7. // 2.告诉子类初始化beanFactory
  8. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
  9. // 3.对beanFactory进行填充属性
  10. prepareBeanFactory(beanFactory);
  11. try {
  12. // 留个子类去实现接口
  13. postProcessBeanFactory(beanFactory);
  14. StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
  15. // 调用beanFactory的后置处理器,会在此将class扫描解析成bean定义
  16. invokeBeanFactoryPostProcessors(beanFactory);
  17. // 注册我们的bean后置处理器
  18. registerBeanPostProcessors(beanFactory);
  19. beanPostProcess.end();
  20. // 初始国际化资源处理器
  21. initMessageSource();
  22. // 创建事件多播器
  23. initApplicationEventMulticaster();
  24. // 这里也是留个子类实现,springboot也是从这里启动tomcat的
  25. onRefresh();
  26. // 把我们的事件监听器注册到多播器上
  27. registerListeners();
  28. // 实例化我们剩余的单实例bean
  29. finishBeanFactoryInitialization(beanFactory);
  30. // 最后容器刷新,发布刷新事件,像springcloud也是从这里启动的
  31. finishRefresh();
  32. }
  33. catch (BeansException ex) {
  34. if (logger.isWarnEnabled()) {
  35. logger.warn("Exception encountered during context initialization - " +
  36. "cancelling refresh attempt: " + ex);
  37. }
  38. // Destroy already created singletons to avoid dangling resources.
  39. destroyBeans();
  40. // Reset 'active' flag.
  41. cancelRefresh(ex);
  42. // Propagate exception to caller.
  43. throw ex;
  44. }
  45. finally {
  46. // Reset common introspection caches in Spring's core, since we
  47. // might not ever need metadata for singleton beans anymore...
  48. resetCommonCaches();
  49. contextRefresh.end();
  50. }
  51. }
  52. }

二、IOC加载过程总结:

1.new一个AnnotationConfigApplicationContext
2.在AnnotationConfigApplicationContext父类的无参构造函数中初始了一个BeanFactory
3.在AnnotationConfigApplicationContext的无参构造函数中创建了配置类的reader和scanner
4.在创建reader的同时也注册了很多处理器,如配置类解析处理器
5.在AnnotationConfigApplicationContext的构造函数中进行Bean注册
6.由bean工厂进行bean实例的创建