spring bean的生命周期详解

spring bean的生命周期详解,第1张

文章目录
  • 序言
  • 流程图
  • 具体过程
    • 1.创建BeanFactory
    • 2.扫描
    • 3.合并BeanDefinition
    • 4.加载类
    • 5.实例化前
    • 6. 实例化
    • 7. BeanDefinition的后置处理
    • 8. 实例化后
    • 9. 填充填充
    • 10. 执行Aware
    • 11. 初始化前
    • 12. 初始化
    • 13. 初始化后
    • 14.bean销毁

序言

Spring最重要的功能就是帮助程序员创建对象(也就是IOC),而启动Spring就是为创建Bean对象做准备,所以我们先明白Spring到底是怎么去创建Bean的,也就是先弄明白Bean的生命周期。

流程图

具体过程

这里省略了一些逻辑,bean生命周期主要逻辑如下

1.创建BeanFactory
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);

spring启动在applicationContext时会构造一个BeanFactory对象

2.扫描

Spring启动的时候会进行扫描,会先调用

org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider#scanCandid
ateComponents(String basePackage) 

扫描某个包路径,并得到BeanDefinition的Set集合。
扫描的逻辑也是比较复杂,后面有时间的话再拿出来单独讲。

3.合并BeanDefinition

由于Spring中支持父子BeanDefinition,所以需要进行BeanDefinition的合并,得到完整的child的BeanDefinition。(很少用这样定义)

<bean id="parent" class="com.zhouyu.service.Parent" scope="prototype"/>
<bean id="child" class="com.zhouyu.service.Child"/>
4.加载类

BeanDefinition合并之后,就可以去创建Bean对象了,而创建Bean就必须实例化对象,而实例化就必须先加载当前BeanDefinition所对应的class
如果beanClass属性的类型是Class,那么就直接返回,如果不是,则会根据类名进行加载(doResolveBeanClass方法所做的事情)会利用BeanFactory所设置的类加载器来加载类,如果没有设置,则默认使用
ClassUtils.getDefaultClassLoader()所返回的类加载器来加载。

5.实例化前

当前BeanDefinition对应的类成功加载后,就可以实例化对象了,但是…
在Spring中,实例化对象之前,Spring提供了一个扩展点,允许用户来控制是否在某个或某些Bean实例化之前做一些启动动作。这个扩展点叫InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation()。比如:

@Component
public class ZhouyuBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName)throws BeansException {
	if ("userService".equals(beanName)) {
		System.out.println("实例化前");
	}
	return null;
	}
}

如上代码会导致,在userService这个Bean实例化前,会进行打印。
值得注意的是,postProcessBeforeInstantiation()是有返回值的,如果这么实现:

@Component
public class ZhouyuBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName)throws BeansException {
	if ("userService".equals(beanName)) {
		System.out.println("实例化前");
		return new UserService();
	}
	return null;
	}
}

userService这个Bean,在实例化前会直接返回一个由我们所定义的UserService对象。如果是这样,表示不需要Spring来实例化了,并且后续的Spring依赖注入也不会进行了,会跳过一些步骤,直接执行初始化后这一步。

6. 实例化

在这个步骤中就会根据BeanDefinition去创建一个对象了。
这里实例化的时候涉及到知识点推断构造方法, 大家可以看我的另一篇博客

7. BeanDefinition的后置处理

Bean对象实例化出来之后,接下来就应该给对象的属性赋值了。在真正给属性赋值之前,Spring又提供了一个扩展点
MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition(),可以对此时的BeanDefinition进行加工,比如:

@Component
public class ZhouyuMergedBeanDefinitionPostProcessor implements MergedBeanDefinitionPostProcessor {
	@Override
	public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition,Class<?> beanType, String beanName) {
		if ("userService".equals(beanName)) {
		beanDefinition.getPropertyValues().add("orderService", new OrderService());
		}
	}
}

在Spring源码中,AutowiredAnnotationBeanPostProcessor就是一个
MergedBeanDefinitionPostProcessor,它的postProcessMergedBeanDefinition()中会去查找注入点,并缓存在AutowiredAnnotationBeanPostProcessor对象的一个Map中
(injectionMetadataCache)。

8. 实例化后

在处理完BeanDefinition后,Spring又设计了一个扩展点:
InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation(),比如:

@Component
public class ZhouyuInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
	@Override
	public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
		if ("userService".equals(beanName)) {
			UserService userService = (UserService) bean;
			userService.test();
		}
	return true;
	}
}

上述代码就是对userService所实例化出来的对象进行处理。
这个扩展点,在Spring源码中基本没有怎么使用。

9. 填充填充

这里的自动注入指的是Spring的自动注入,也就是填充属性(依赖注入)
这个步骤中,就会处理@Autowired、@Resource、@Value等注解,
这其中的逻辑也比较复杂,后面有时间的话再拿出来单独讲。

10. 执行Aware

完成了属性赋值之后,Spring会执行一些回调,包括:

  1. BeanNameAware:回传beanName给bean对象。
  2. BeanClassLoaderAware:回传classLoader给bean对象。
  3. BeanFactoryAware:回传beanFactory给对象。
11. 初始化前

初始化前,也是Spring提供的一个扩展点:
BeanPostProcessor.postProcessBeforeInitialization(),比如

@Component
public class ZhouyuBeanPostProcessor implements BeanPostProcessor {
	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		if ("userService".equals(beanName)) {
			System.out.println("初始化前");
		}
	return bean;
	}
}

利用初始化前,可以对进行了依赖注入的Bean进行处理。

12. 初始化
  1. 查看当前Bean对象是否实现了InitializingBean接口,如果实现了就调用其afterPropertiesSet()方法
  2. 执行BeanDefinition中指定的初始化方法
13. 初始化后

这是Bean创建生命周期中的最后一个步骤,也是Spring提供的一个扩展点:
BeanPostProcessor.postProcessAfterInitialization(),比如:

@Component
public class ZhouyuBeanPostProcessor implements BeanPostProcessor {
	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		if ("userService".equals(beanName)) {
			System.out.println("初始化后");
		}
	return bean;
	}
}

可以在这个步骤中,对Bean最终进行处理,Spring中的AOP就是基于初始化后实现的,初始化后返回的对象才是最终的Bean对象。

14.bean销毁

Bean销毁是发送在Spring容器关闭过程中的。
在Spring容器关闭时,比如:

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
UserService userService = (UserService) context.getBean("userService");
userService.test();
// 容器关闭
context.close();

在Bean创建过程中,在最后(初始化之后),有一个步骤会去判断当前创建的Bean是不是DisposableBean:

  1. 当前Bean是否实现了DisposableBean接口
  2. 或者,当前Bean是否实现了AutoCloseable接口
  3. BeanDefinition中是否指定了destroyMethod
  4. 调用DestructionAwareBeanPostProcessor.requiresDestruction(bean)进行判断
    i. ApplicationListenerDetector中直接使得ApplicationListener是DisposableBean
    ii. InitDestroyAnnotationBeanPostProcessor中使得拥有@PreDestroy注解了的方法就是
    DisposableBean
  5. 把符合上述任意一个条件的Bean适配成DisposableBeanAdapter对象,并存入
    disposableBeans中(一个LinkedHashMap)

在Spring容器关闭过程时:

  1. 首先发布ContextClosedEvent事件
  2. 调用lifecycleProcessor的onCloese()方法
  3. 销毁单例Bean
    1. 遍历disposableBeans
      1. 把每个disposableBean从单例池中移除
      2. 调用disposableBean的destroy()
      3. 如果这个disposableBean还被其他Bean依赖了,那么也得销毁其他Bean
      4. 如果这个disposableBean还包含了inner beans,将这些Bean从单例池中移除掉(inner bean参考https://docs.spring.io/springframework/docs/current/springframework-reference/core.html#beans-inner-beans)
    2. 清空manualSingletonNames,是一个Set,存的是用户手动注册的单例Bean的beanNam
    3. 清空allBeanNamesByType,是一个Map,key是bean类型,value是该类型所有的beanName数组
    4. 清空singletonBeanNamesByType,和allBeanNamesByType类似,只不过只存了单例Bean

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/871015.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-13
下一篇 2022-05-13

发表评论

登录后才能评论

评论列表(0条)

保存