Spring 底层源码之bean的生命周期(四)

本文详细解析了Spring中Bean的生命周期,包括从bean定义的生成、加载类、实例化、属性注入、初始化到销毁的全过程。特别讨论了@LookUp注解的用法,以及在doGetBean和doScan方法中的源码实现,揭示了Spring如何管理单例和原型bean。同时,介绍了如何处理依赖注入、初始化回调以及销毁方法的注册。
摘要由CSDN通过智能技术生成

1. bean的生命周期

① 生成bean定义,合并bean定义(父子关系)

② 加载类

③ 实例化前

④ 实例化:Supplier创建对象 || 工厂方法创建对象 || 推断构造方法

⑤ bean定义的后置处理

⑥ 实例化后

⑦ 自动注入

⑧ 处理属性:

⑨ 执行Aware

⑩ 初始化

⑪ 初始化后

2. 扫描bean的底层源码(doScan)

① 扫描配置类中的@ComponentScan包路径,遍历扫描到的资源文件

② 利用ASM技术获取到元数据:

  1. 根据ExcludeFilter过滤
  2. 根据IncludeFilter筛选:① 要有@Component注解 ② 如果有@Conditional注解,需要判断是否满足条件(SpringBoot 用的比较多)。

③ 构造bean定义,属性赋值:比如metaData(类的元数据)、beanClass(这里是类的全限定名,后面创建bean用这个加载)

④ 进一步筛选:过滤非静态内部类、接口类、没有@LookUp修饰方法的抽象类

①->④属于findCandidateComponents(basePackage);的过程

⑤ 遍历筛选后的bean定义,属性赋值:setScope、setBeanName、解析@Lazy、@Primary、@DependsOn、@Role、@Description

⑥ 检查Spring容器中是否存在这个beanName,不存在,注册Bean定义,存在抛异常:重复的beanName

3. @LookUp注解其它用法

@Component
Class UserService{
    @Autowired
    private User user;
    
    void test(){
        system.out.println(user);
    }
}

@Component
@Scope("prototype")
public class User{

}

// 测试...
UserService userService = (UserService) context.getBean("userService");
userService.test();
userService.test();
userService.test();
// 测试结果:都是打印同一个user对象,因为UserService 是单例的,user属性只会注入一次不
@Component
Class UserService{
    @Autowired
    private User user;
    
    void test(){
        system.out.println(findUser());
    }
    
    @Lookup("user")
    public User findUser(){
        return null;
    }
}

// 添加@Lookup修饰的方法,那么就会打印不同的user

4. 创建非懒加载的单例bean:finishBeanFactoryInitialization(beanFactory)

① 遍历beanNames,合并bean定义(如果有父子关系的bean定义),缓存到mergedBean定义Map

② 根据bean定义属性值,判断不是抽象的是单例并且不是懒加载

1. 不是抽象的:不是指抽象类,因为抽象类就不会创建bean定义,这里指bean定义不是抽象的,基于xml配置bean设置抽象的bean定义,即abstract = true

2. 抽象的bean定义有什么用:自己不能创建bean,但是可以供子类继承,创建子类。子类继承,会继承父类的bean属性,即合并bean定义,生成新的RootBeanDefinition

③ 判断是否FactoryBean

  1. 是,先创建普通的bean。判断如果实现的是SmartFactoryBean,重写isEagerInit()方法可以做到Spring启动的时候就调用getObject()提前创建好真正的bean,缓存到factoryBeanMap中

如果实现的不是SmartFactoryBean,在getBean()的时候才会创建调用getObject()方法创建真正的bean返回

  1. 否,创建普通的bean

④ 以上完成非懒加载的bean全部创建,然后遍历bean,判断是否实现SmartInitializingSingleton。如果是,这里就会调用aferSingletonsInstantiated()方法

5.doGetBean底层源码:

① 根据beanName,从单例池中找,没有找到则开始创建

② 获取bean定义,判断dependsOn属性值,如果不为空,将被依赖关系注册到dependentBeanMap中,然后会先创建@DependsOn注解依赖的bean

③ 判断是单例,还是原型,还是其它Scope,然后创建bean

1. 创建单例bean,涉及到单例池。从单例池中获取,获取不到执行传入的lambda表达式创建bean,创建完再放到单例池中,关键代码如下

2. 创建原型bean,就直接创建

if (mbd.isSingleton()) {
   sharedInstance = getSingleton(beanName, () -> {
      try {
         return createBean(beanName, mbd, args);
      }
      catch (BeansException ex) {
         // Explicitly remove instance from singleton cache: It might have been put there
         // eagerly by the creation process, to allow for circular reference resolution.
         // Also remove any beans that received a temporary reference to the bean.
         destroySingleton(beanName);
         throw ex;
      }
   });
   bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}

6.创建bean底层源码:

① 如果bean对应的类,还没有加载,需要完成类加载

② 获取后置处理器,判断如果不为空,遍历执行实例化前的回调方法。比如执行实例化前的回调方法,自己创建bean返回,而不是由Spring创建bean。

但是还会经过初始化后,为了兼容AOP

③ 如果没有后置处理器干预bean的创建,Spring开始实例化bean(doCreateBean)

④ 推断构造方法,实例化bean。获取后置处理器,执行修改bean定义的回调方法。这里就是执行@Autowired、@Resource的后置处理器,解析注入点缓存起来

程序可以在这里添加后置处理器,干预bean实例化后的逻辑,比如通过给bean定义设置初始化方法、属性填充等操作

⑤ 属性填充:

  1. 获取后置处理器,判断如果不为空,遍历执行实例化后的回调方法
  2. 处理Spring自带的注解属性autowire,比如@Bean(autowire=Autowire.BY_NAME)
    1. 判断bean类中的所有属性,有对应的set方法,且不是基本类型,才会处理
    2. BY_NAME,根据set方法后面的名字作为beanName,从容器中找对象,进行属性赋值
    3. BY_TYPE,根据set方法的参数类型,从容器中找对象,进行属性赋值
  3. 执行后置处理器,属性填充的回调方法。这里就是执行@Autowired、@Value、@Resource的后置处理器,进行属性填充
    1. @Autowired属性填充的过程:所有被@Autowired修饰的属性和方法都是注入点,在前面步骤已经被提前解析
      1. 注解在字段上,先根据字段类型找bean
      2. 注解在方法上:如果是无参的,直接利用反射调用方法。如果是有参的,参数值先根据类型找bean,利用反射执行该方法
      3. 如果字段或者方法参数根据类型找到多个bean:
        1. 如果使用了@Primary、@Priority(''数字')、@Qualifer("名字")修饰,会直接取优先级最高的bean
        2. 如果没有使用以上注解,再根据bean的名字找bean,最终没有找到会报错
        3. 如果属性或方法参数使用@Lazy注解修饰,注入的是代理对象,只有到真正使用对象调用方法时,执行代理逻辑去容器中找这个bean,然后通过bean调用该方法
    2. @Resource属性填充的过程:所有被@Autowired修饰的属性和方法都是注入点,在前面步骤已经被提前解析
      1. 是否指定bean的名字和bean的类型,没有指定使用默认的
      2. 使用@Lazy注解修饰,直接注入代理对象
      3. 先根据bean的名字找,找不到再根据类型找
      4. Java级别的,Spring做了支持。如果不使用Spring框架,就要使用@Resource

⑥ 初始化

  1. 判断bean是否实现Aware接口,执行回调方法,比如BeanNameWare setBeanName()、ApplicationContextWare setApplicationContext() 回传需要的对象
  2. 获取后置处理器,遍历执行初始化前的回调方法。Spring添加了处理@PostConstruct的后置处理器
  3. 获取后置处理器,遍历执行初始化后的回调方法。如果开启AOP,这里就是执行AOP的后置处理器,判断是否需要创建代理对象

⑦ 寻找bean销毁方法,缓存起来。在Spring容器关闭时,会执行bean销毁的方法

  1. springmvc、springboot底层就是向JVM进程注册一个关闭钩子,当进程正常关闭的时候会触发bean销毁的方法,强制关闭进程是不会执行的
  2. 实现bean销毁:
    1. 实现接口
    2. 使用@PreDestroy修饰方法

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值