Spring容器Bean创建流程源码初解析

1.首先 下载spring-framework源码到本地,并且倒入idea使用gradle进行构建,构建过程错误大多可以通过gradle的build解决。

https://github.com/spring-projects/spring-framework/tree/5.1.x

2.在spring-framework下面在创建一个gradle构建的module,并且创建Main(测试函数入口),Example1,Example2(两个Bean),AppConfig(配置文件)

各类中的结构:Example1 与Example2 分别为两个bean,相互引用

AppConfig.java

@ComponentScan(basePackages = "com.fplei.lib")
@Configuration
public class AppConfig {

}

Example1.java

@Component
public class Example1 {
   @Autowired
   private Example2 example2;

   public Example1() {
      System.out.println("Example1 init");
   }
   public void invokeExample2(){
      example2.test2();
   }
   @PostConstruct
   public void getInstance(){
      System.out.println("PostConstruct--》getInstance");
   }

   @PreDestroy
   public void onDestory(){
      System.out.println("PostConstruct--》onDestory");
   }
}

Example2.java

@Component
public class Example2 implements InitializingBean {
   @Autowired
   private Example1 example1;

   public Example2() {
      System.out.println("--->Example2");
   }
   public void test2(){
      System.out.println("test2");
   }
   @Override
   public void afterPropertiesSet() throws Exception {
      System.out.println("Example2 初始化完成-->afterPropertiesSet");
   }
   @PostConstruct
   public void getInstance(){
      System.out.println("PostConstruct--》Example2.getInstance");
   }
   @PreDestroy
   public void onDestory(){
      System.out.println("PostConstruct--》Example2.onDestory");
   }
}

Main.java

//实例化Example1,通过example1调用Example2的方法
public static void main(String[] args){
   //这里采用注解配置文件的ApplicationContext
   AnnotationConfigApplicationContext configApplicationContext=new AnnotationConfigApplicationContext(AppConfig.class);
   Example1 example1=(Example1)configApplicationContext.getBean("example1");
   example1.invokeExample2();
}

3.从AnnotationConfigApplicationContext开始

Spring容器运行非常简单,一句代码就能自动运行。那么先从这个类类似分析容器运行创建bean过程,进入AnnotationConfigApplicationContext源码可以看出其构造器调用了如下方法:

....
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
   this();
   register(componentClasses);
   refresh();
}
...

this():跟进代码发现是初始化Bean扫描器

register():注册spring系统运行内部类以及加载解析符合spring的bean,包装成BeanDefinition。

refresh():跟进该方法发现这个refresh才是bean创建的开始入口,源码如下:

...
@Override
public void refresh() throws BeansException, IllegalStateException {
   synchronized (this.startupShutdownMonitor) {
      //1 准备上下文
      prepareRefresh();
      //2 Tell the subclass to refresh the internal bean factory.
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
      //3 Prepare the bean factory for use in this context.
      prepareBeanFactory(beanFactory);
      try {
         //4 允许在上下文子类中对bean工厂进行后处理
         postProcessBeanFactory(beanFactory);
         //5 调用工厂处理器,这里可以自定义操作(该步骤重要)
         invokeBeanFactoryPostProcessors(beanFactory);
         //6 注册BeanPostProcessor
         registerBeanPostProcessors(beanFactory);
         //7 Initialize message source for this context.
         initMessageSource();
         //8 Initialize event multicaster for this context.
         initApplicationEventMulticaster();
         //9 Initialize other special beans in specific context subclasses.
         onRefresh();
         //10 Check for listener beans and register them.
         registerListeners();
         //11 实例化,初始化等操作(该步骤重要)
         finishBeanFactoryInitialization(beanFactory);
         //12 Last step: publish corresponding event.
         finishRefresh();
      }
      ……省略….
   }
}

再refresh方法中一共有12处方法调用,其中和Bean创建直接关联较多的是invokeBeanFactoryPostProcessors,

finishBeanFactoryInitialization

两个方法,接下来分别看下这2个方法各自实现。

4.invokeBeanFactoryPostProcessors

执行该方法后将实例化并调用所有注册的BeanFactoryPostProcessorBean,被执行的代码在

org.springframework.context.support.PostProcessorRegistrationDelegate中,源码如下

如上我们定义了一个类 MyBeanFactoryPostProcessor,该类将在beanfactory初始化时被调用

@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
   @Override
   public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
      System.out.println(beanFactory.toString());
   }
}

在类实现方法中我们可以获取到被扫描的bean,可以做一些自己的逻辑操作。