Spring容器Bean的周期扩展点浅析

116 阅读3分钟

使用Spring开发时,当我们向容器中添加Bean时,希望在bean创建、使用或销毁时,执行一些额外动作,又该如何实现呢?

其实,Spring容器对Bean生命周期提供了很多扩展点,我们只需实现接口或使用注解,就能让容器在合适时机,回调自定义的业务逻辑。

今天,一起来看看下面4个扩展点:

  • @PostConstruct
  • InitializingBean接口
  • SmartInitializingSingleton接口
  • DisposableBean接口

一 @PostConstruct

该注解来自javax.annotation包,部分源码注释: image.png 概括重点如下:

  • @PostConstruct,用于需要在依赖注入完成后执行任何初始化的方法上;
  • 这个方法必须在类投入使用之前调用;
  • 该方法不能有任何参数,除非在拦截器的情况下;
  • 不限制方法权限修饰符,public、protected、private都可以,是由反射调用;
  • 方法不可以是static的,但可以是final的;
  • 如果该方法抛出未检查的异常,则该类绝对不能投入服务,除非EJB可以处理异常甚至从中恢复。

作用:在依赖注入完成后、类投入使用之前被调用,执行一些初始化逻辑。

import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;

@Service
public class UserService {

  @PostConstruct
  public void init(Long id) {
    System.out.println("hello");

  }
}

当方法有参数时,springboot启动时将报错 image.png

二 InitializingBean接口

image.png Spring框架中的一个扩展接口,afterPropertiesSet方法,会在bean的属性被设置值之后、调用@Bean的initMethod方法之前,被spring自动调用。

用途:在创建Bean时,可以修改默认属性值,添加额外属性,或者执行一些校验;

InitializingBean接口,与@Bean的init-method属性对应的方法功能是一致的,实战中可以二选一即可,同时使用也没有问题。

来看看@PostConstruct、afterPropertiesSet、@Bean的initMethod执行顺序。 定义一个UserService类,在启动类创建一个实例。

import org.springframework.beans.factory.InitializingBean;
import javax.annotation.PostConstruct;

public class UserService implements InitializingBean {

  @PostConstruct
  public void postConstruct() {
    System.out.println("PostConstruct");
  }

  @Override
  public void afterPropertiesSet() throws Exception {
    System.out.println("afterPropertiesSet");
  }

  public void customInit() {
    System.out.println("customInit");
  }
}
import com.learn.more.service.UserService;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class MoreApplication {

  public static void main(String[] args) {
    SpringApplication.run(MoreApplication.class, args);
  }

  @Bean(initMethod = "customInit")
  public UserService userService() {
    return new UserService();
  }
}

image.png 可见,执行顺序上:@PostConstruct > afterPropertiesSet > @Bean的initMethod

三 SmartInitializingSingleton接口

当所有单例bean初始化完成后,Spring容器会调用实现了该接口的bean的afterSingletonsInstantiated()方法。

使用场景是在所有单例 bean 创建完成之后,可以在该回调中做一些初始化工作,常用于整合中间件

例如xxl-job(开源的分布式调度框架)源码(2.4.0版本)中,被spring集成时,XxlJobSpringExecutor类实现SmartInitializingSingleton接口,在afterSingletonsInstantiated方法中加载了执行器并start启动。 image.png 在应用程序中使用xxl-job时,只需创建XxlJobSpringExecutor类示例,并交给spring容器管理即可。 image.png

四 DisposableBean接口

通过实现DisposableBean接口并重写destroy()方法,可以在Spring容器销毁bean时执行回调,确保业务资源的优雅释放。 image.png

比如在xxl-job源码(2.4.0版本)中,XxlJobSpringExecutor类实现了DisposableBean接口。 image.png 当spring容器销毁这个bean时,将释放xxl-job中所有线程、关闭Netty。 image.png