【框架源码】Spring源码解析之Bean生命周期流程

在这里插入图片描述

观看本文前,我们先思考一个问题,什么是Spring的bean的生命周期?这也是我们在面试的时候,面试官常问的一个问题。

在没有Spring之前,我们创建对象的时候,采用new的方式,当对象不在被使用的时候,由Java的垃圾回收机制回收。

而 Spring 中的对象是 bean,bean 和普通的 Java 对象没啥大的区别,只不过 Spring 不再自己去 new 对象了,而是由 IoC 容器去帮助我们实例化对象并且管理它,我们需要哪个对象,去问 IoC 容器要即可。IoC 其实就是解决对象之间的耦合问题,Spring Bean 的生命周期完全由容器控制。

在这里,我们主要是针对bean 的作用域为singleton的,对于 prototype 的 bean ,Spring 在创建好交给使用者之后则不会再管理后续的生命周期。

那么bean的作用域都有哪些,我们来回顾一下。

singleton : 唯一 bean 实例,Spring 中的 bean 默认都是单例的。

prototype : 每次请求都会创建一个新的 bean 实例。

request : 每一次 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前 HTTP request 内有效。

session : 每一次 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前 HTTP session 内有效。

global-session: 全局 session 作用域,仅仅在基于 Portlet 的 web 应用中才有意义,Spring5 已经被删除。

Spring Bean 的生命周期核心就分为以下几步:

  • 实例化 Instantiation
  • 属性赋值 Populate
  • 初始化 Initialization
  • 销毁 Destruction

实例化 -> 属性赋值 -> 初始化 -> 销毁

在这里插入图片描述

ok,接下来,我们用一个bean的创建来体验下Spring Bean的生命周期。

首先,我们先来介绍下什么是FactoryBean?

扫描二维码关注公众号,回复: 15383697 查看本文章

FactoryBean要和BeanFactory区分开来,BeanFactory是一个Bean工厂,创建和管理bean的工厂,是顶级接口,而FactoryBean 用来自定义Bean的创建过程,完成复杂Bean的定义。

Spring中Bean主要有有两种,一个是定义普通Bean,另一个是工厂Bean(FactoryBean)。FactoryBean是一个工厂bean,可以生成某一个类型的Bean实例,通过实现该接口定制实例化bean的逻辑。

FactoryBean在Spring框架中非常重要,Spring自身就提供了70多个FactoryBean接口的实现,通过 getBean()方法返回的不是FactoryBean本身,而是FactoryBean#getObject()方法所返回的对象,相当于FactoryBean#getObject()代理了getBean()方法。

FactoryBean接口源码:

public interface FactoryBean<T> {
    
    

  String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";

  //返回由FactoryBean 创建的Bean实例,如果isSingleton()返回true,该实例会被放到Spring容器的单里缓存池中
  @Nullable
  T getObject() throws Exception;

  //返回FactoryBean创建的Bean的类型
  @Nullable
  Class<?> getObjectType();

  //判断Bean的作用域是singleton还是prototype
  default boolean isSingleton() {
    
    
    return true;
  }
}

案例实战

  • 配置文件中< bean >的class属性配置的实现类是FactoryBean时,通过getBean()方法返回的不是FactoryBean本身
  • 获取的是FactoryBean#getObject()方法所返回的对象,相当于FactoryBean#getObject()代理了getBean()方法。
  • 创建Order实体类
@Data
public class Order {
    
    
		//订单ID
    private int orderId;
		//订单名称
    private String orderName;
		//订单价格
    private int price;
}
  • 创建OrderFactoryBean
public class OrderFactoryBean implements FactoryBean<Order> {
    
    

    public OrderFactoryBean() {
    
    
        System.out.println("FactoryBean构造方法执行");
    }

    private String orderInfo;
  
  	//设置orderInfo
    public void setOrderInfo(String orderInfo) {
    
    
        this.orderInfo = orderInfo;
    }

    // 11@测试订单@7999
    @Override
    public Order getObject() throws Exception {
    
    
        String[] split = orderInfo.split("@");
        Order order = new Order();
        order.setOrderId(Integer.parseInt(split[0]));
        order.setOrderName(split[1]);
        order.setPrice(Integer.parseInt(split[2]));
        return order;
    }
		//返回当前bean类型
    @Override
    public Class<?> getObjectType() {
    
    
        return Order.class;
    }
		//返回当前bean是否为单例
    @Override
    public boolean isSingleton() {
    
    
        return FactoryBean.super.isSingleton();
    }
}
  • xml配置文件
    <bean id="order" class="com.lixiang.factory.OrderFactoryBean">
        <property name="orderInfo" value="11@测试订单@7999"/>
    </bean>
  • 主类测试
    public static void main(String[] args) {
    
    
        ApplicationContext context =  new ClassPathXmlApplicationContext("classpath*:application.xml");

        Order order = (Order) context.getBean("order");
        System.out.println(order);

        Object obj =  context.getBean("&order");
        System.out.println(obj);
    }

在这里插入图片描述

接下来,我们再来看一下BeanFactoryPostProcessor。

BeanFactoryPostProcessor是Spring框架中一个重要的扩展接口,可以在spring的bean创建之前,可以修改Bean的定义属性,注入第三方数据等。它是在 Spring 容器加载定义 bean 的 XML 文件之后,在 bean 实例化之前执行的,对Bean进行后置处理。它的执行逻辑在BeanFactory初始化时执行,在BeanFactory的后置处理器(BeanPostProcessor)之前执行。

作用:

  • 读取应用程序上下文(ApplicationContext)中的所有Bean定义。
  • 修改定义中的属性值等信息。
  • 对修改后的定义进行处理,使其达到预期效果。
  • 将修改后的Bean定义反馈到容器中,容器将重新执行Bean创建和初始化的过程

接口代码

//ConfigurableListableBeanFactory 可以获取bean定义信息,里面进行修改bean定义
public interface BeanFactoryPostProcessor {
    
    
  void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}

案例实战

  • 定义一个 OrderBeanFactoryPostProcessor,修改某个 bean 从单例改为多例,然后触发init方法。
public class OrderBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    
    

    public OrderBeanFactoryPostProcessor(){
    
    
        System.out.println("OrderBeanFactoryPostProcessor构造方法执行");
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    
    
        String[] beanStr = beanFactory.getBeanDefinitionNames();
        for (String beanName : beanStr) {
    
    
            if ("order".equals(beanName)) {
    
    
                BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
                beanDefinition.setScope(ConfigurableBeanFactory.SCOPE_SINGLETON);
            }
        }
    }

    //testInit 初始化方法
    public void testInit(){
    
    
        System.out.println("OrderBeanFactoryPostProcessor testInit 方法被调用,执行初始化逻辑");
    }
}

  • 配置xml
<bean id="customFactoryPostProcessor" class="com.lixiang.factory.OrderBeanFactoryPostProcessor" init-method="testInit"></bean>
  • 编写测试主类
	public static void main(String[] args) {
    
    
        ApplicationContext context =  new ClassPathXmlApplicationContext("classpath*:application.xml");
        Object obj1 =  context.getBean("&order");
        Object obj2 =  context.getBean("&order");
        System.out.println(obj1);
        System.out.println(obj2);
    }

在这里插入图片描述

Ok,说完BeanFactoryPostProcessor,我们再来看下BeanPostProcessor。

BeanPostProcessor是Spring IOC容器提供的一个扩展机制,用于拦截和修改实例化的Bean对象的过程。默认是对整个Spring容器中【所有的bean】进行处理,如果要对具体某个bean进行处理,通过方法参数判断即可。在容器实例化Bean对象后 (执行构造函数),初始化方法执行【前后】的回调方法,提供Bean实例初始化期间加入自定义逻辑。

案例实战

  • 编写OrderBeanPostProcessor
public class OrderBeanPostProcessor implements BeanPostProcessor {
    
    
    public OrderBeanPostProcessor() {
    
    
        System.out.println("BeanPostProcessor构造方法执行");
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    
    
        return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
    }

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

        System.out.println("BeanPostProcessor postProcessAfterInitialization 调用 beanName="+beanName);
        if(beanName.equalsIgnoreCase("order")){
    
    
            Order order = (Order)bean;
            order.setOrderName("修改后的订单名称");
            return BeanPostProcessor.super.postProcessAfterInitialization(order, beanName);
        }
        return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
    }
}
  • 编写xml配置Order对象属性
    <bean id="orderBeanPostProcessor" class="com.lixiang.factory.OrderBeanPostProcessor"></bean>
    <bean id="order" class="com.lixiang.domain.Order">
        <property name="orderId" value="113726"/>
      	<!-- 这里我们将订单名称设置为测试订单 -->
        <property name="orderName" value="测试订单"/> 
        <property name="price" value="2131213"/>
    </bean>
  • 编写测试代码
	public static void main(String[] args) {
    
    
        ApplicationContext context = new ClassPathXmlApplicationContext("classpath*:application.xml");

        Order order = (Order) context.getBean("order");
        System.out.println(order);

    }

在这里插入图片描述

  • 注意

    • BeanPostProcessor 是在 spring 容器加载了 bean 的定义文件,且实例化 bean 之后执行

    • BeanPostProcessor 的执行顺序是在 BeanFactoryPostProcessor 之后

    • BeanFactoryPostProcessor 和 BeanPostProcessor 都是处理 bean 的生命周期中拓展点,使用场景不同

      • BeanFactoryPostProcessor 作用于 bean 实例化之前,读取配置元数据 BeanDefinition ,且可以修改
      • BeanPostProcessor 作用于 bean 的实例化过程中,可以改变 bean 实例的值

还有几个接口,我们简单了解下,这快就不做演示了。

  • BeanNameAware
BeanNameAware接口是为了让自身Bean能够感知到,获取到自身在Spring容器中的id或name属性。让Bean获取自己在BeanFactory配置中的名字(根据情况是id或者name)。 

Spring自动调用。并且会在Spring自身完成Bean配置之后,且在调用任何Bean生命周期回调(初始化或者销毁)方法之前就调用这个方法。换言之,在程序中使用BeanFactory.getBean(String beanName)之前,Bean的名字就已经设定好了。
  • BeanFactoryAware
BeanFactoryAware接口是Spring框架中的一个接口,用于在Bean实例化后,将BeanFactory实例注入到Bean中。通过实现该接口,Bean可以获取到BeanFactory实例,从而可以在运行时动态获取其他Bean的实例。

具体来说,BeanFactoryAware接口的作用是让Bean能够感知到所在的BeanFactory,从而可以在需要时获取其他Bean的实例。这对于需要动态获取其他Bean的实例的情况非常有用,例如在AOP中需要获取代理对象等。
  • ApplicationContextAware
在spring项目中,类之间的关系是spring容器来管理的,但是一个项目中有些类不受spring容器管理,缺需要使用受spring管理的bean,这时候不能通过正常的方式注入bean,这时候spring给我们提供了ApplicationContextAware接口,我们可以编写一个工具类来实现ApplicationContextAware,当一个类实现ApplicationContextAware接口后,当这个类被spring加载后,就能够在这个类中获取到spring的上下文操作符ApplicationContext,通过ApplicationContext 就能够轻松的获取所有的spring管理的bean。
  • Initializingbean
Initializingbean接口只有一个afterPropertiesSet方法,实现了这个接口的类在初始化Bean时会执行这个方法。所以这个接口的用途就是用来实现初始化数据用的。

public interface InitializingBean {
    
    
    void afterPropertiesSet() throws Exception;
}
  • DisposableBean
该接口的作用是:允许一个bean在它的所有必须属性被BeanFactory设置后,来执行初始化的工作,该接口中只有一个方法,afterPropertiesSet。

public interface InitializingBean {
    
    
    void afterPropertiesSet() throws Exception;
}

ok,现在我们用Order实现以上的接口。

public class Order implements BeanNameAware, BeanFactoryAware,
        ApplicationContextAware, InitializingBean, DisposableBean {
    
    

    private int orderId;

    private String orderName;

    private int price;

    public Order() {
    
    
        System.out.println("Order - 构造方法执行,创建对象");
    }

    public Order(int orderId, String orderName, int price) {
    
    
        this.orderId = orderId;
        this.orderName = orderName;
        this.price = price;
    }

    public int getOrderId() {
    
    
        return orderId;
    }

    public void setOrderId(int orderId) {
    
    
        this.orderId = orderId;
    }

    public String getOrderName() {
    
    
        return orderName;
    }

    public void setOrderName(String orderName) {
    
    
        this.orderName = orderName;
    }

    public int getPrice() {
    
    
        return price;
    }

    public void setPrice(int price) {
    
    
        this.price = price;
    }

    @Override
    public String toString() {
    
    
        return "Order{" +
                "orderId=" + orderId +
                ", orderName='" + orderName + '\'' +
                ", price=" + price +
                '}';
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
    
    
        System.out.println("Order - BeanFactoryAware - setBeanFactory 方法被调用");
    }

    @Override
    public void setBeanName(String s) {
    
    
        System.out.println("Order - BeanNameAware - setBeanName 方法被调用");
    }

    @Override
    public void destroy() throws Exception {
    
    
        System.out.println("Order - DisposableBean - destroy 方法被调用");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
    
    
        System.out.println("Order - InitializingBean - afterPropertiesSet 方法被调用");
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    
    
        System.out.println("Order - ApplicationContextAware - setApplicationContext 方法被调用");
    }
}

创建Order对象,查看方法执行调用链。

在这里插入图片描述

方法调用链图解

在这里插入图片描述

源码分析目标,关键就在于AbstractApplicationContext 类 的 refresh 方法

在这里插入图片描述

OK,接下来我们来看看refresh的源码分析,基本上整一个spring生命周期都这这个方法里执行,我们来看看这个核心方法里面都做了什么

public void refresh() throws BeansException, IllegalStateException {
    
    
    //采用对象锁,保证多线程环境下,在容器正在启动/关闭时, 另一个启动/关闭操作会被阻塞
    synchronized (this.startupShutdownMonitor) {
    
    
      //统计Spring应用程序的启动时间,并输出到log
      StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");

      //1.调用子类覆盖的方法prepareRefresh(),为当前的工厂进行启动数据准备工作
      prepareRefresh();

      /**
       * 2.调用子类覆盖的方法obtainFreshBeanFactory(),创建新的BeanFactory, 默认实现是DefaultListableBeanFactory
       * 解析xml, 生成BeanDefinition 并注册到 BeanDefinitionRegistry
       *
       */
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

      //3.beanFactory准备工作,调用子类覆盖的方法prepareBeanFactory(),对新的BeanFactory进行各种后置处理
      prepareBeanFactory(beanFactory);

      try {
    
    
        //4.beanFactory准备工作完成后,继续进行的【后置处理】
        postProcessBeanFactory(beanFactory);

        StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");

        //5.BeanFactoryPostProcessor
        //Spring 启动时查找所有实现 BeanFactoryPostProcessor 接口的类,并逐一调用其 postProcessBeanFactory 方法
        invokeBeanFactoryPostProcessors(beanFactory);

        //6.BeanPostProcessor
        //注册 BeanPostProcessor,负责为该 Bean 对象创建代理对象
        registerBeanPostProcessors(beanFactory);
        beanPostProcess.end();

        //7.初始化信息源,用来支持国际化
        initMessageSource();

        //8.初始化事件广播器,用来支持了Spring事件机制
        initApplicationEventMulticaster();

        //9.留给子类实现的初始化操作,即调用自定义的回调方法
        onRefresh();

        //10.注册实现了ApplicationListener接口的类
        registerListeners();

        /**
         * 11.实例化所有剩余的单例Bean(非懒加载的单例bean),注意这里要区分单例和非单例Bean,主要下面的工作
         *    填充属性
         *    调用初始化方法 afterPropertiesSet、init-method方法
         *    调用BeanPostProcessor 后置处理器 postProcessBeforeInitialization和postProcessAfterInitialization执行
         */
        finishBeanFactoryInitialization(beanFactory);

        //12.事件发布,发送ContextRefreshedEvent事件
        finishRefresh();
      }

      catch (BeansException ex) {
    
    
        if (logger.isWarnEnabled()) {
    
    
          logger.warn("Exception encountered during context initialization - " +
              "cancelling refresh attempt: " + ex);
        }

        // Destroy already created singletons to avoid dangling resources.
        // 销毁已经创建的单例bean
        destroyBeans();

        // 将 context 的 active 属性重置为 false
        cancelRefresh(ex);

        // Propagate exception to caller.
        throw ex;
      }

      finally {
    
    
        // Reset common introspection caches in Spring's core, since we
        // might not ever need metadata for singleton beans anymore...
        // 重置Spring IOC中的共享缓存,避免单例bean的引用问题
        resetCommonCaches();
        //更新contextRefresh的状态
        contextRefresh.end();
      }
    }
  }

总结

  • 首先根据配置情况调用 Bean 构造方法或工厂方法实例化 Bean。

  • 然后利用反射创建对象设置Bean 中所有属性值的配置注入。

  • 如果 Bean 实现了 BeanNameAware 接口,则 Spring 调用 Bean 的 setBeanName() 方法传入当前 Bean 的 id 值。

  • 如果 Bean 实现了 BeanFactoryAware 接口,则 Spring 调用 setBeanFactory() 方法传入当前工厂实例的引用。

  • 如果 Bean 实现了 ApplicationContextAware 接口,则 Spring 调用 setApplicationContext() 方法传入当前 ApplicationContext 实例的引用。

  • 如果 BeanPostProcessor 和 Bean 关联,则 Spring 将调用该接口的预初始化方法 postProcessBeforeInitialzation() 对 Bean 进行加工操作,此处非常重要,Spring 的 AOP 就是利用它实现的。

  • 如果 Bean 实现了 InitializingBean 接口,则 Spring 将调用 afterPropertiesSet() 方法,如果在配置文件中通过 init-method 属性指定了初始化方法,则调用该初始化方法。

  • 如果 BeanPostProcessor 和 Bean 关联,则 Spring 将调用该接口的初始化方法 postProcessAfterInitialization()。此时,Bean 已经可以被应用系统使用了。

  • 如果在 中指定了该 Bean 的作用范围为 scope=“singleton”,则将该 Bean 放入 Spring IoC 的缓存池中,将触发 Spring 对该 Bean 的生命周期管理;如果在 中指定了该 Bean 的作用范围为 scope=“prototype”,则将该 Bean 交给调用者,调用者管理该 Bean 的生命周期,Spring 不再管理该 Bean。

  • 如果 Bean 实现了 DisposableBean 接口,则 Spring 会调用 destory() 方法将 Spring 中的 Bean 销毁;如果在配置文件中通过 destory-method 属性指定了 Bean 的销毁方法,则 Spring 将调用该方法对 Bean 进行销毁。

ok,那么至此,Spring Bean的整一个生命周期全部解析完成。
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_47533244/article/details/131045777
今日推荐