# SpringBean的生命周期

## 生命周期

对于普通的java对象，当new的时候创建对象，当它没有任何引用的时候被垃圾回收机制回收。而Spring Ioc容器托管的对象，它们的生命周期完全由容器控制。Spring Bean的声明周期如下：

![](https://3037548586-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LnpynfpU0w3FBTJVlOK%2Fsync%2F79084133ce3034b74585bf5b2abde17cb32b1634.png?generation=1589894636441737\&alt=media)

整个生命周期流程如下：

1. Spring对Bean进行初始化 **（此时执行构造器）**
2. Spring将值和Bean的引用注入Bean对应的属性中
3. 如果Bean实现了BeanNameAware接口，Spring将Bean的ID传递给setBeanName(String name)方法 **（实现BeanNameAware清主要是为了通过Bean的引用来获得Bean的ID，一般业务中是很少有用到Bean的ID的**）
4. 如果Bean实现了BeanFactoryAware接口，Spring将调用setBeanFactory方法并把BeanFactory容器实例作为参数传入。 **（实现BeanFactoryAware 主要目的是为了获取Spring容器，如Bean通过Spring容器发布事件等）**
5. 如果Bean实现了ApplicationContextAware接口，Spring容器将调用setApplicationContext(ApplicationContext ctx)方法，把应用上下文作为参数传入。 **(作用与BeanFactory类似都是为了获取Spring容器，不同的是ApplicationContextAware继承自BeanFactory，所以除了BeanFactory的所有功能，还提供了很多其他强大功能 )**
6. 当经过上述几个步骤后，bean对象已经被正确构造，但如果你想要对象被使用前再进行一些自定义的处理，就可以通过BeanPostProcessor接口实现。 **注意：这个接口作用于所有的Bean** 该接口提供了两个函数：
   * postProcessBeforeInitialzation( Object bean, String beanName ) 当前正在初始化的bean对象会被传递进来，我们就可以对这个bean作任何处理。 这个函数会先于InitialzationBean执行，因此称为前置处理。 所有Aware接口的注入就是在这一步完成的。
   * postProcessAfterInitialzation( Object bean, String beanName ) 当前正在初始化的bean对象会被传递进来，我们就可以对这个bean作任何处理。 这个函数会在InitialzationBean完成后执行，因此称为后置处理。
7. 当BeanPostProcessor的前置处理完成后就会进入InitializingBean接口。

   这一阶段也可以在bean正式构造完成前增加我们自定义的逻辑，但它与前置处理不同，由于该函数并不会把当前bean对象传进来，因此在这一步没办法处理对象本身，只能增加一些额外的逻辑。 若要使用它，我们需要让bean实现该接口，并把要增加的逻辑写在该函数中。然后Spring会在前置处理完成后检测当前bean是否实现了该接口，并执行afterPropertiesSet函数。

   当然，Spring为了降低对客户代码的侵入性，给bean的配置提供了init-method属性，该属性指定了在这一阶段需要执行的函数名。Spring便会在初始化阶段执行我们设置的函数。init-method本质上仍然使用了InitializingBean接口。
8. 经过以上的工作后，Bean将一直驻留在应用上下文中给应用使用，直到应用上下文被销毁
9. 如果Bean实现了DisposableBean接口，Spring将调用它的destory方法，作用与在配置文件中对Bean使用destory-method属性的作用一样，都是在Bean实例销毁前执行的方法。

## BeanFactoryPostProcessor

BeanFactoryPostProcessor与BeanPostProcessor不同的是：

1. BeanFactoryPostProcessor在所有Bean初始化之前执行，也就是最开始的地方；
2. BeanFactoryPostProcessor只执行一次，而BeanPostProcessor在每个Bean生成周期期间都会执行；

BeanFactoryPostProcessor可以对Bean的配置元数据（XML中配置的bean的属性）进行处理。如果你需要在所有Bean初始化之前执行一段逻辑并且只执行一次，选择BeanFactoryPostProcessor在合适不过了。

使用示例：

```java
public class Test implements BeanPostProcessor, BeanFactoryPostProcessor {

  	// 所有Bean初始化的时候都会执行
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("enter Test.postProcessBeforeInitialization, beanName:" + beanName);
        return bean;
    }

  	// 所有Bean初始化之前执行一次
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        System.out.println("enter Test.postProcessBeanFactory, beanName:" + configurableListableBeanFactory.getBeanDefinition("shareInterface").getBeanClassName());
    }
}
```

## SmartLifecycle

SmartLifecycle 在容器所有bean加载和初始化完毕执行。

有时候我们需要在Spring加载和初始化所有bean后，接着执行一些任务或者启动需要的异步服务，这样我们可以使用 SmartLifecycle 来做到。SmartLifecycle 是一个接口。当Spring容器加载所有bean并完成初始化之后，会接着回调实现该接口的类中对应的方法（start()方法）。除了start方法，其他方法的作用如下：

```java
// 所有bean初始化完成后执行，只有isAutoStartup返回true才会被执行
public void start() {
  
}

// 该方法只对直接实现接口Lifecycle的类才起作用，对实现SmartLifecycle接口的类无效
// 方法stop()和方法stop(Runnable callback)的区别只在于，后者是SmartLifecycle子类的专属。
public void stop() {

}

// 只有该方法返回false时，start方法才会被执行。
// 只有该方法返回true时，stop(Runnable callback)或stop()方法才会被执行。
public boolean isRunning() {
  return false;
}

// true:执行start方法，false:不执行start方法(默认)
public boolean isAutoStartup() {
  return false;
}

// 当isRunning方法返回true时，该方法才会被调用。
public void stop(Runnable callback) {
				// 如果你让isRunning返回true，需要执行stop这个方法，那么就不要忘记调用callback.run()。
        // 否则在你程序退出时，Spring的DefaultLifecycleProcessor会认为你这个TestSmartLifecycle没有stop完成，程序会一直卡着结束不了，等待一定时间（默认超时时间30秒）后才会自动结束。
        // PS：如果你想修改这个默认超时时间，可以按下面思路做，当然下面代码是springmvc配置文件形式的参考，在SpringBoot中自然不是配置xml来完成，这里只是提供一种思路。
        // <bean id="lifecycleProcessor" class="org.springframework.context.support.DefaultLifecycleProcessor">
        //      <!-- timeout value in milliseconds -->
        //      <property name="timeoutPerShutdownPhase" value="10000"/>
        // </bean>
}

// 如果工程中有多个实现接口SmartLifecycle的类，则这些类的start的执行顺序按getPhase方法返回值从小到大执行。
// 例如：1比2先执行，-1比0先执行。 stop方法的执行顺序则相反，getPhase返回值较大类的stop方法先被调用，小的后被调用。
public int getPhase() {
  return 0;
}
```

## 小技巧

```java
// 1. 获取某个类的所有Bean实例的name
String[] beanNames = context.getBeanNamesForType(TestBean.class);
```

> 参考：<https://www.zhihu.com/question/38597960>
