深入探究Spring中Bean的生命周期

你好,我柳岸花开。

在使用Spring框架时,我们经常会听到关于Bean的生命周期的概念。本文将深入探讨Bean的生命周期,从Bean的生成到销毁,逐步解析Spring框架中的关键步骤。

什么是Bean的生命周期?

Bean的生命周期指的是Bean在Spring容器中的生成、初始化、使用和销毁的整个过程。在这个过程中,Spring框架负责管理Bean的创建和销毁,同时允许开发者通过扩展点来干预Bean的行为,以满足特定需求。

Bean的生成过程

在Spring中,Bean的生成过程是通过IOC(控制反转)实现的。下面我们来详细了解一下Bean的生成过程:

// 入口代码
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
UserService userService = (UserService) applicationContext.getBean("userService");
userService.test();

生成BeanDefinition:

在Spring启动时,会扫描指定的包路径,得到所有的BeanDefinition。

扫描类文件流程如下:

  1. 首先,通过ResourcePatternResolver获得指定包路径下的所有.class文件(Spring源码中将此文件包装成了Resource对象)
  2. 遍历每个Resource对象
  3. 利用MetadataReaderFactory解析Resource对象得到MetadataReader(在Spring源码中MetadataReaderFactory具体的实现类为CachingMetadataReaderFactory,MetadataReader的具体实现类为SimpleMetadataReader)
  4. 利用MetadataReader进行excludeFilters和includeFilters,以及条件注解@Conditional的筛选(条件注解并不难理解:某个类上是否存在@Conditional注解,如果存在则调用注解中所指定的类的match方法进行匹配,匹配成功则通过筛选,匹配失败则pass掉。)
  5. 筛选通过后,基于metadataReader生成ScannedGenericBeanDefinition
  6. 再基于metadataReader判断是不是对应的类是不是接口或抽象类
  7. 如果筛选通过,那么就表示扫描到了一个Bean,将ScannedGenericBeanDefinition加入结果集。

CachingMetadataReaderFactory解析某个.class文件得到MetadataReader对象是利用的ASM技术,并没有加载这个类到JVM。最终得到的ScannedGenericBeanDefinition对象,beanClass属性存储的是当前类的名字,而不是class对象。(beanClass属性的类型是Object,它即可以存储类的名字,也可以存储class对象)

为什么要使用ASM技术,Spring启动的时候需要去扫描,如果指定的包路径比较宽泛,那么扫描的类是非常多的,那如果在Spring启动时就把这些类全部加载进JVM了,这样不太好,所以使用了ASM技术。

ASM是一个java字节码操纵框架,它能被用来动态生成类或者增强既有类的功能; .class字节码是有严格的格式的,ASM可以通过格式来解析字节码,得到类名称、方法、属性等信息; ASM比jdk反射技术性能更高; JVM类加载是懒加载的,通过ASM来获取类信息,更节省JVM性能;

合并BeanDefinition:

Spring支持父子BeanDefinition的合并,以及工厂方法创建Bean。

加载类:

根据BeanDefinition中的类名加载对应的类,这一步是实例化对象的前提条件。

// 加载类
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);

if (mbd.hasBeanClass()) {
    // 如果beanClass属性的类型是Class,那么就直接返回
 return mbd.getBeanClass();
}
// 根据类名加载
if (System.getSecurityManager() != null) {
 return AccessController.doPrivileged((PrivilegedExceptionAction<Class<?>>) () ->
  doResolveBeanClass(mbd, typesToMatch), getAccessControlContext());
 }
else {
    // 利用BeanFactory所设置的类加载器来加载类,如果没有设置,则默认使用ClassUtils.getDefaultClassLoader()所返回的类加载器来加载。
 return doResolveBeanClass(mbd, typesToMatch);
}

实例化前扩展点:

Spring提供了InstantiationAwareBeanPostProcessor扩展点,允许在实例化对象之前进行一些操作。

// 实例化前扩展点
@Component
public class BobBeanPostProcessor implements InstantiationAwareBeanPostProcessor {

 @Override
 public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
  // 注意,此时还没有实例化,所以能拿到的是beanClass
        if ("userService".equals(beanName)) {
   System.out.println("实例化前");
            // 可以返回值,非null时,表示不需要Spring来实例化了,并且后续的Spring依赖注入也不会进行了,会跳过一些步骤,直接执行初始化后这一步
            return new UserService();
  }
  return null;
 }
}

实例化Bean:

根据BeanDefinition创建对象实例,可以通过Supplier创建、工厂方法创建或者推断构造方法创建等方式。

BeanDefinition的后置处理:

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

@Component
public class BobMergedBeanDefinitionPostProcessor 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)。

实例化后:

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

@Component
public class BobInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {

 @Override
 public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {

  if ("userService".equals(beanName)) {
   UserService userService = (UserService) bean;
   userService.test();
  }

  return true;
 }
}

处理属性:

这个步骤中,就会处理@Autowired、@Resource、@Value等注解,也是通过InstantiationAwareBeanPostProcessor.postProcessProperties()扩展点来实现的。

@Component
public class BobInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {

 @Override
 public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
  if ("userService".equals(beanName)) {
   for (Field field : bean.getClass().getFields()) {
    if (field.isAnnotationPresent(FireInject.class)) {
     field.setAccessible(true);
     try {
      field.set(bean, "123");
     } catch (IllegalAccessException e) {
      e.printStackTrace();
     }
    }
   }
  }

  return pvs;
 }
}

执行Aware:

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

BeanNameAware:回传beanName给bean对象。

BeanClassLoaderAware:回传classLoader给bean对象。

BeanFactoryAware:回传beanFactory给对象。

初始化前:

初始化前,也是Spring提供的一个扩展点:BeanPostProcessor.postProcessBeforeInitialization()。 利用初始化前,可以对进行了依赖注入的Bean进行处理。

@Component
public class BobBeanPostProcessor implements BeanPostProcessor {

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

  return bean;
 }
}

InitDestroyAnnotationBeanPostProcessor会在初始化前这个步骤中执行@PostConstruct的方法, ApplicationContextAwareProcessor会在初始化前这个步骤中进行其他Aware的回调:
- EnvironmentAware:回传环境变量
- EmbeddedValueResolverAware:回传占位符解析器
- ResourceLoaderAware:回传资源加载器
- ApplicationEventPublisherAware:回传事件发布器
- MessageSourceAware:回传国际化资源
- ApplicationStartupAware:回传应用其他监听对象,可忽略
- ApplicationContextAware:回传Spring容器ApplicationContext

初始化

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

初始化后

这是Bean创建生命周期中的最后一个步骤,也是Spring提供的一个扩展点:BeanPostProcessor.postProcessAfterInitialization()。 可以在这个步骤中,对Bean最终进行处理,Spring中的AOP就是基于初始化后实现的,初始化后返回的对象才是最终的Bean对象。

@Component
public class FireBeanPostProcessor implements BeanPostProcessor {

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

  return bean;
 }
}

总结

  1. 实例化前(InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation())
  2. 实例化
  3. 合并Bean(MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition())
  4. 实例化后(InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation())
  5. 自动注入
  6. 属性赋值(InstantiationAwareBeanPostProcessor.postProcessProperties())
  7. Aware对象
  8. 初始化前(BeanPostProcessor.postProcessBeforeInitialization())
  9. 初始化
  10. 初始化后(BeanPostProcessor.postProcessAfterInitialization())

Bean的销毁过程

与生成过程相对应,Bean的销毁过程发生在Spring容器关闭时。下面是Bean销毁的主要步骤:

// Bean的销毁过程
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
UserService userService = (UserService) context.getBean("userService");
userService.test();

// 容器关闭
context.close();

在Spring容器关闭过程时:

  1. 首先发布ContextClosedEvent事件
  2. 调用lifecycleProcessor的onCloese()方法
  3. 销毁单例Bean

1.遍历disposableBeans,把每个disposableBean从单例池中移除,调用disposableBean的destroy()。如果这个disposableBean还被其他Bean依赖了,那么也得销毁其他Bean;如果这个disposableBean还包含了inner beans,将这些Bean从单例池中移除掉。
2.清空manualSingletonNames,是一个Set,存的是用户手动注册的单例Bean的beanName
3.清空allBeanNamesByType,是一个Map,key是bean类型,value是该类型所有的beanName数组
4.清空singletonBeanNamesByType,和allBeanNamesByType类似,只不过只存了单例Bean

最后

通过以上步骤,我们可以清晰地了解Spring框架中Bean的生命周期。掌握Bean的生命周期对于深入理解Spring框架的运作机制和实现原理非常重要,也有助于我们在实际开发中更好地利用Spring框架的功能。

希望本文能够帮助您更好地理解Spring中Bean的生命周期,如果有任何疑问或意见,请随时留言交流。

本文由 mdnice 多平台发布

相关推荐

  1. 深入探究SpringBean生命周期

    2024-03-23 00:34:03       32 阅读
  2. 深入探索 Spring Bean 生命周期自定义扩展方法

    2024-03-23 00:34:03       22 阅读
  3. spring bean生命周期

    2024-03-23 00:34:03       58 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-03-23 00:34:03       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-03-23 00:34:03       101 阅读
  3. 在Django里面运行非项目文件

    2024-03-23 00:34:03       82 阅读
  4. Python语言-面向对象

    2024-03-23 00:34:03       91 阅读

热门阅读

  1. AIGC创业者的宝贵资源库

    2024-03-23 00:34:03       44 阅读
  2. 力扣hot100题解(python版96-100题)

    2024-03-23 00:34:03       39 阅读
  3. Microsoft SQL Server 编写汉字转拼音函数

    2024-03-23 00:34:03       42 阅读
  4. Python实现批量修改文件名(附带源码)

    2024-03-23 00:34:03       42 阅读
  5. Python判断一个数是否为素数

    2024-03-23 00:34:03       37 阅读
  6. 【力扣二刷思路】DAY5

    2024-03-23 00:34:03       42 阅读
  7. vmware中ubuntu虚拟机桥接模式和xshell连接

    2024-03-23 00:34:03       44 阅读
  8. 【mybatis】TypeAliasRegistry解读

    2024-03-23 00:34:03       42 阅读
  9. LeetCode-热题100:283.移动零

    2024-03-23 00:34:03       39 阅读
  10. Docker compose()

    2024-03-23 00:34:03       44 阅读