使用Spring开发时,当我们向容器中添加Bean时,希望在bean创建、使用或销毁时,执行一些额外动作,又该如何实现呢?
其实,Spring容器对Bean生命周期提供了很多扩展点,我们只需实现接口或使用注解,就能让容器在合适时机,回调自定义的业务逻辑。
今天,一起来看看下面4个扩展点:
- @PostConstruct
- InitializingBean接口
- SmartInitializingSingleton接口
- DisposableBean接口
一 @PostConstruct
该注解来自javax.annotation包,部分源码注释:
概括重点如下:
- @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启动时将报错
二 InitializingBean接口
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();
}
}
可见,执行顺序上:@PostConstruct > afterPropertiesSet > @Bean的initMethod
三 SmartInitializingSingleton接口
当所有单例bean初始化完成后,Spring容器会调用实现了该接口的bean的afterSingletonsInstantiated()方法。
使用场景是在所有单例 bean 创建完成之后,可以在该回调中做一些初始化工作,常用于整合中间件。
例如xxl-job(开源的分布式调度框架)源码(2.4.0版本)中,被spring集成时,XxlJobSpringExecutor类实现SmartInitializingSingleton接口,在afterSingletonsInstantiated方法中加载了执行器并start启动。
在应用程序中使用xxl-job时,只需创建
XxlJobSpringExecutor类示例,并交给spring容器管理即可。
四 DisposableBean接口
通过实现DisposableBean接口并重写destroy()方法,可以在Spring容器销毁bean时执行回调,确保业务资源的优雅释放。
比如在xxl-job源码(2.4.0版本)中,XxlJobSpringExecutor类实现了DisposableBean接口。
当spring容器销毁这个bean时,将释放xxl-job中所有线程、关闭Netty。