spring bean生命周期详解,源码分析

目录

  • 简介
  • 如何获取bean
  • ClassPathXmlApplicationContext方法
  • refresh源码分析
  • finishBeanFactoryInitialization(beanFactory):
  • spring bean的完整生命周期
  • 进阶版spring bean的完整生命周期

简介

  • 在传统的Java应用中,bean的生命周期很简单,使用Java关键字 new 进行Bean 的实例化,然后该Bean 就能够使用了。一旦bean不再被使用,则由Java自动进行垃圾回收。
  • 相比之下,Spring管理Bean的生命周期就复杂多了,正确理解Bean 的生命周期非常重要,因为Spring对Bean的管理可扩展性非常强。
  • Spring 只帮我们管理单例模式 Bean 的完整生命周期,对于 prototype 的 bean ,Spring 在创建好交给使用者之后则不会再管理后续的生命周期。

如何获取bean

首先,我们在代码中是怎样获取bean的,方式有以下几种,但不局限于这两种:

 @Test
    public void run1(){
     
        //加载配置文件
        ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
        //获取对象
        AccountService as =(AccountService)ac.getBean("accountService");
        //调用方法
        as.findAll();
    }

 @Test
    public void run2(){
     
    	//传入配置类的类实例来告诉spring配置类是哪一个
        ApplicationContext ac = new ClassPathXmlApplicationContext(JavaConfig.class);
        //获取对象
        AccountService as =(AccountService)ac.getBean("accountService");
        //调用方法
        as.findAll();

ApplicationContext是spring中比较高级的容器。和BeanFactory类似,它可以加载配置文件中定义的bean,并将所有bean集中在一起,当有请求的时候分配bean。
Application接口实现:
FileSystemXmlApplicationContext:该容器从xml文件中加载已被定义的bean。在这里,你需要提供给构造器XML文件的完整路径
ClassPathXmlApplicationContext:该容器从xml文件中加载已经被定义的bean,在这里你不需要提供xml文件的完整路径,只需要正确配置Classpath环境变量即可,因为,容器会从Classpath中搜索bean配置文件

AnnotationConfigApplicationContext其实和xml的原理一致。只是xml方式bean被定义在xml文件中,而Annotation方式是将bean定义在一个java类文件中
一个是ClassPathXmlApplicationContext,基于classpath下的xml配置文件;另一种是AnnotationConfigApplicationContext,基于java配置文件。

让我们来看一下他们的继承关系,注意看红线框住的类和接口
spring bean生命周期详解,源码分析_第1张图片
spring bean生命周期详解,源码分析_第2张图片

ClassPathXmlApplicationContext方法

现在我们以ClassPathXmlApplicationContext为例,来进行源码的讲解
首先进入ClassPathXmlApplicationContext()之后,他会进入相应的构造方法中

public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
     
		this(new String[] {
     configLocation}, true, null);
	}

再此调用本类中的对应的构造函数

	public ClassPathXmlApplicationContext(
			String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
			throws BeansException {
     
		//一直调用父类构造,直到 AbstractApplicationContext,设置一个空的 ApplicationContext 对象
		super(parent);
		设置配置文件路径
		setConfigLocations(configLocations);
		默认为 true
		if (refresh) {
     
			//调用的是AbstractApplicationContext类refresh()方法,实现的ConfigurableApplicationContext接口中的refresh()方法
			refresh();
		}
	}

refresh源码分析

重点到了:refresh(),这个方法就是bean生命周期的关键点,调用的是AbstractApplicationContext类refresh()方法,实现的ConfigurableApplicationContext接口中的refresh()方法(可以看一下上面的关系图)
我们在看这个方法之前,先要知道一些脉络,以帮助我们更好的理解代码(下图为借鉴马士兵老师的图)

spring bean生命周期详解,源码分析_第3张图片

  • 不管是是通过xml配置文件的标签,还是通过注解配置的@Bean,还是@Compontent标注的类,还是扫描得到的类,它最终都会被解析成一个BeanDefinition对象,最后我们的Bean工厂就会根据这份Bean的定义信息,对bean进行实例化、初始化等等操作。
  • 你可以把BeanDefinition丢给Bean工厂,然后Bean工厂就会根据这个信息帮你生产一个Bean实例,拿去使用。
  • BeanDefinition里面里面包含了bean定义的各种信息,如:bean对应的class、scope等信息

源码分析

@Override
	public void refresh() throws BeansException, IllegalStateException {
     
		synchronized (this.startupShutdownMonitor) {
     
			//为容器初始化做准备
			prepareRefresh();

			// 解析xml和注解
			//该方法会解析所有 Spring 配置文件(通常我们会放在 resources 目录下),将所有 Spring 配置文件中的 bean 定义封装成 BeanDefinition,加载到 BeanFactory 中。
      //加载 bean 定义,由 XmlWebApplicationContext 实现
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			//前面已经把配置类的定义已经注册到容器中,还在进行对配置类进行全面分析和处理之前,Spring还要再做一些预处理,比如设置类加载器,设置后置处理器ApplicationContextAwareProcessor,将environment  systemProperties systemEnvironment三个对象添加到容器当中,设置Spring框架不需要被自动注入的接口等操作。
			prepareBeanFactory(beanFactory);

			try {
     
				      
        //这里面代码是空的
        // 由子类实现对BeanFacoty的一些后置处理
				postProcessBeanFactory(beanFactory);

				/* 本方法会实例化和调用所有 BeanFactoryPostProcessor
        BeanFactoryPostProcessors:bean工厂的bean属性处理容器,说通俗一些就是可以管理我们的bean工厂内所有的beandefinition(未实例化)数据,可以随心所欲的修改属性。*/
				invokeBeanFactoryPostProcessors(beanFactory);

				/*本方法会注册所有的 BeanPostProcessor,将所有实现了 BeanPostProcessor 接口的类加载到 BeanFactory 中。
        BeanPostProcessor 接口是 Spring 初始化 bean 时对外暴露的扩展点,Spring IoC 容器允许 BeanPostProcessor 在容器初始化 bean 的前后,添加自己的逻辑处理。在 registerBeanPostProcessors 方法只是注册到 BeanFactory 中,具体调用是在 bean 初始化的时候。
				具体的:在所有 bean 实例化时,执行初始化方法前会调用所有 BeanPostProcessor 的 postProcessBeforeInitialization 方法,在执行初始化方法后会调用所有 BeanPostProcessor 的 postProcessAfterInitialization 方法。*/
				registerBeanPostProcessors(beanFactory);

				//初始化ApplicationContext的MessageSource
				initMessageSource();

				//初始化ApplicationContext事件广播器
				initApplicationEventMulticaster();

				// 初始化子类特殊bean(钩子方法)
				onRefresh();

				// 注册事件监听器
				registerListeners();

				/*
				* 1、bean实例化过程
				* 2、依赖注入
				* 3、解析@PostConstruct,@PreDestroy,@Resource, @Autowired,@Value等注解
				* 4、BeanPostProcessor的执行
				* 5、Aop的入口
				*
				* */
				finishBeanFactoryInitialization(beanFactory);

				// 广播事件,ApplicationContext初始化完成
				finishRefresh();
			}

			catch (BeansException ex) {
     
				...
			}

			finally {
     
				...
			}
		}
	}

finishBeanFactoryInitialization(beanFactory):

首先我们先看一张流程图,理清脉络

spring bean生命周期详解,源码分析_第4张图片

  1. 首先在preInstantiateSingletons方法中判断:单例非懒加载非抽象,满足这三个条件才会调用getBean(Bean实例化都是通过调用该方法实现的)实例化
  2. getBean中会调用doGetBean,doGetBean中从缓存中拿实例,没有的话则通过scope类型去创建对应的Bean实例,在创建对象之前如果scope是prototype类型的首先会通过
  3. 有的话调用getSingleton(beanName),经过一系列的方法调用,调到doCreateBean,进行Bean的实例化,和对象中的属性注入、检查Aware相关接口,BeanPostProcessor的前置处理,BeanPostProcessor的后置处理,初始化的操作

spring bean的完整生命周期

(1)实例化Bean:

对于BeanFactory容器,当客户向容器请求一个尚未初始化的bean时,或初始化bean的时候需要注入另一个尚未初始化的依赖时,容器就会调用createBean进行实例化。对于ApplicationContext容器,当容器启动结束后,通过获取BeanDefinition对象中的信息,实例化所有的bean。

(2)设置对象属性(依赖注入):

实例化后的对象被封装在BeanWrapper对象中,紧接着,Spring根据BeanDefinition中的信息 以及 通过BeanWrapper提供的设置属性的接口完成依赖注入。

(3)处理Aware接口:

接着,Spring会检测该对象是否实现了xxxAware接口,并将相关的xxxAware实例注入给Bean:

①如果这个Bean已经实现了BeanNameAware接口,会调用它实现的setBeanName(String beanId)方法,此处传递的就是Spring配置文件中Bean的id值;

②如果这个Bean已经实现了BeanFactoryAware接口,会调用它实现的setBeanFactory()方法,传递的是Spring工厂自身。

③如果这个Bean已经实现了ApplicationContextAware接口,会调用setApplicationContext(ApplicationContext)方法,传入Spring上下文;

(4)BeanPostProcessor:

如果想对Bean进行一些自定义的处理,那么可以让Bean实现了BeanPostProcessor接口,那将会调用postProcessBeforeInitialization(Object obj, String s)方法。

(5)InitializingBean 与 init-method:

如果Bean在Spring配置文件中配置了 init-method 属性,则会自动调用其配置的初始化方法。

(6)如果这个Bean实现了BeanPostProcessor接口,将会调用postProcessAfterInitialization(Object obj, String s)方法;由于这个方法是在Bean初始化结束时调用的,所以可以被应用于内存或缓存技术;

以上几个步骤完成后,Bean就已经被正确创建了,之后就可以使用这个Bean了。

(7)DisposableBean:

当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean这个接口,会调用其实现的destroy()方法;

(8)destroy-method:

最后,如果这个Bean的Spring配置中配置了destroy-method属性,会自动调用其配置的销毁方法。

进阶版spring bean的完整生命周期

  1. 我们先在我们需要获取bean对象的方法中调用ApplicationContext容器,将XML文件或者JAVA文件作为参数传到对应的容器中
  2. 启动时,容器会帮我们设置配置文件路径,调用AbstractApplicationContext类refresh()方法,实现的ConfigurableApplicationContext接口中的refresh()方法(refresh()方法,它的作用就是:在创建IOC 容器前,如果已经有容器存在,则需要把已有的容器销毁和关闭,以保证在refresh 之后使用的是新建立起来的IOC 容器。refresh 的作用类似于对IOC 容器的重启,在新建立好的容器中对容器进行初始化,对Bean 定义资源进行载入。)
  3. 在refresh()方法中调用obtainFreshBeanFactory方法进行解析XML和注解,并加载Bean定义,注册到IOC容器中。
  4. 然后调用prepareBeanFactory方法做一些预处理,比如设置类加载器
  5. 之后调用invokeBeanFactoryPostProcessors方法管理我们的bean工厂内所有的beandefinition(未实例化)数据,可以再此时对数据进行修改操作
  6. 在调用registerBeanPostProcessors方法注册所有的 BeanPostProcessor,将所有实现了 BeanPostProcessor 接口的类加载到 BeanFactory 中,Spring IoC 容器允许 BeanPostProcessor 在容器初始化 bean 的前后,添加自己的逻辑处理。
  7. 之后会做一些初始化容器的一些工作和注册事件监听器
  8. 接下来就是调用finishBeanFactoryInitialization方法进行bean对象的处理
  9. 首先判断:单例非懒加载非抽象,满足这三个条件才会调用getBean(Bean实例化都是通过调用该方法实现的)实例化
  10. getBean中会调用doGetBean,doGetBean中从缓存中拿实例,没有的话则通过scope类型去创建对应的Bean实例,在创建对象之前如果scope是prototype类型的首先会通过isPrototypeCurrentlyInCreation检验是否存在循环依赖
  11. 有的话调用getSingleton(beanName),经过一系列的方法调用,调到doCreateBean,在此方法中调用createBeanInstance方法进行Bean的实例化,通过获取BeanDefinition对象中的信息,实例化所有的bean。
  12. 在调用populateBean,完成对对象属性的设置(依赖注入),实例化后的对象被封装在BeanWrapper对象中,紧接着,Spring根据BeanDefinition中的信息 以及 通过BeanWrapper提供的设置属性的接口完成依赖注入。
  13. 在通过调用initializebean方法中的invokeAwareMethods方法,检测该对象是否实现了xxxAware接口,并将相关的xxxAware实例注入给Bean:
    ①如果这个Bean已经实现了BeanNameAware接口,会调用它实现的setBeanName(String beanId)方法,此处传递的就是Spring配置文件中Bean的id值;
    ②如果这个Bean已经实现了BeanFactoryAware接口,会调用它实现的setBeanFactory()方法,传递的是Spring工厂自身。
    ③如果这个Bean已经实现了ApplicationContextAware接口,会调用setApplicationContext(ApplicationContext)方法,传入Spring上下文;
  14. 如果想对Bean进行一些自定义的处理,那么可以让Bean实现了BeanPostProcessor接口,那将会调用postProcessBeforeInitialization()方法。可以在初始化前对bean进行操作
  15. 如果Bean在Spring配置文件中配置了 init-method 属性,则会自动调用其配置的初始化方法。
  16. 如果这个Bean实现了BeanPostProcessor接口**,将会调用postProcessAfterInitialization()方法,可以初始化后对bean进行操作
  17. 接下来就可以使用bean了
  18. 当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean这个接口,会调用其实现的destroy()方法;
  19. 如果这个Bean的Spring配置中配置了destroy-method属性,会自动调用其配置的销毁方法。

你可能感兴趣的:(Spring,spring,java,ioc)