SpringBoot 扩展性接口

时间:2022-10-16 16:00:18


1.可扩展的接口启动调用顺序图

​org.springframework.beans.factory.xxx​​​​org.springframework.boot.xxx​

​org.springframework.context.xxx​

SpringBoot 扩展性接口

  1. ApplicationContextInitializer.initialize
  2. AbstractApplicationContext.refresh
  3. BeanDefinitionRegistryPostProcessor.postProcessBeanDefinitionRegistry
  4. BeanDefinitionRegistryPostProcessor.postProcessBeanFactory
  5. InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation
  6. SmartInstantiationAwareBeanPostProcessor.determineCandidateConstructors
  7. MergedBeanDefinitionPostProcessor.postProcessorMergedBeanDefinition
  8. InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation
  9. SmartInstantiationAwareBeanPostProcessor.getEarlyBeanReference
  10. BeanFactoryAware.setBeanFactory
  11. InstantiationAwareBeanPostProcessor.postProcessPropertyValues
  12. ApplicationContextAwareProcessor.invokeAwareInterfaces
  13. BeanNameAware.setBeanName
  14. InstantiationAwareBeanPostProcessor.postProcessBeforeInitialization
  15. @PostConstruct
  16. InitiallzingBean.afterPropertiesSet
  17. InstantiationAwareBeanPostProcessor.postProcessAfterInitialization
  18. FactoryBean.getObject
  19. SmartInitilallzingSingleton.afterSingletonInstantiated
  20. CommondLineRunner.run
  21. DisposableBean.destry

2.ApplicationContextInitializer

​org.springframework.context.ApplicationContextInitializer​

这是整个spring容器在刷新之前初始化​​ConfigurableApplicationContext​​的回调接口,简单来说,就是在容器刷新之前调用此类的initialize方法。这个点允许被用户自己扩展。用户可以在整个spring容器还没被初始化之前做一些事情。

可以想到的场景可能为,在最开始​​激活一些配置​​​,或者利用这时候class还没被类加载器加载的时机,进行​​动态字节码注入​​等操作。

public class TestApplicationContextInitializer implements ApplicationContextInitializer {      
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
System.out.println("[ApplicationContextInitializer]");
}
}

因为这时候spring容器还没被初始化,所以想要自己的扩展的生效,有以下三种方式:

  • 在启动类中用​​springApplication.addInitializers(new TestApplicationContextInitializer())​​语句加入
  • 配置文件配置​​context.initializer.classes=com.example.demo.TestApplicationContextInitializer​
  • Spring SPI扩展,在spring.factories中加入​​org.springframework.context.ApplicationContextInitializer=com.example.demo.TestApplicationContextInitializer​

3.BeanDefinitionRegistryPostProcessor

​org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor​

这个接口在读取项目中的beanDefinition之后执行,提供一个补充的扩展点

使用场景:你可以在这里动态注册自己的beanDefinition,可以加载classpath之外的bean

public class TestBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {      
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
System.out.println("[BeanDefinitionRegistryPostProcessor] postProcessBeanDefinitionRegistry");
}

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("[BeanDefinitionRegistryPostProcessor] postProcessBeanFactory");
}
}

4.BeanFactoryPostProcessor

​org.springframework.beans.factory.config.BeanFactoryPostProcessor​

这个接口是beanFactory的扩展接口,调用时机在spring在读取beanDefinition信息之后,实例化bean之前。

在这个时机,用户可以通过实现这个扩展接口来自行处理一些东西,比如​​修改已经注册的beanDefinition的元信息​​。

public class TestBeanFactoryPostProcessor implements BeanFactoryPostProcessor {      
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("[BeanFactoryPostProcessor]");
}
}

5.InstantiationAwareBeanPostProcessor

​org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor​

继承了​​BeanPostProcessor​​​, 而​​BeanPostProcessor​​​只在bean的初始化阶段进行扩展, 而​​InstantiationAwareBeanPostProcessor​​接口则在初始化阶段, 实例化阶段和属性注入阶段

public class TestInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {      

@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("[TestInstantiationAwareBeanPostProcessor] before initialization " + beanName);
return bean;
}

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("[TestInstantiationAwareBeanPostProcessor] after initialization " + beanName);
return bean;
}

@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
System.out.println("[TestInstantiationAwareBeanPostProcessor] before instantiation " + beanName);
return null;
}

@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
System.out.println("[TestInstantiationAwareBeanPostProcessor] after instantiation " + beanName);
return true;
}

@Override
public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
System.out.println("[TestInstantiationAwareBeanPostProcessor] postProcessPropertyValues " + beanName);
return pvs;
}
  • postProcessBeforeInstantiation: 实例化bean之前,相当于new这个bean之前
  • postProcessAfterInstantiation: 实例化bean之后, 相当与new这个bean之后
  • postProcessPropertyValues: bean 已经实例化以后, 在属性注入阶段触发, @Autowired和@Resource基于此方法
  • postProcessBeforeInitialization: 初始化bean之前, 相当于把bean注入spring上下文之前
  • postProcessAfterInitialization: 初始化bean之后, 相当于把bean注入spring上下文之后

写中间件和业务中,都能利用这个特性。比如对实现了某一类接口的bean在各个生命期间进行收集,或者对某个类型的bean进行统一的设值等等。

6.SmartInstantiationAwareBeanPostProcessor

​org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor​

public class TestSmartInstantiationAwareBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor {      

@Override
public Class<?> predictBeanType(Class<?> beanClass, String beanName) throws BeansException {
System.out.println("[TestSmartInstantiationAwareBeanPostProcessor] predictBeanType " + beanName);
return beanClass;
}

@Override
public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) throws BeansException {
System.out.println("[TestSmartInstantiationAwareBeanPostProcessor] determineCandidateConstructors " + beanName);
return null;
}

@Override
public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
System.out.println("[TestSmartInstantiationAwareBeanPostProcessor] getEarlyBeanReference " + beanName);
return bean;
}
}
  • predictBeanType: 该触发点发生在postProcessBeforeInstantiation之前, 这个方法用于预测Bean的类型, 返回第一个预测成功的Class类型, 如果不能预测返回null。当你调用BeanFactory.getType(name)时当通过bean的名字无法得到bean类型信息时就调用该回调方法来决定类型信息。
  • determineCandidateConstructors: 该触发点发生在postProcessBeforeInstantiation之后, 用于确定bean的构造函数, 返回的是bean的所以构造函数列表, 可以通过此方法自定义选择对应的构造器来实例化bean
  • getEarlyBeanReference: 该触发点发生在postProcessAfterInstantiation之后, 当有循环依赖的场景,当bean实例化好之后,为了防止有循环依赖,会提前暴露回调方法,用于bean实例化的后置处理。这个方法就是在提前暴露的回调方法中触发。

7.BeanFactoryAware

​org.springframework.beans.factory.BeanFactoryAware​

发生在bean的实例化之后,注入属性之前,也就是Setter之前。这个类的扩展点方法为setBeanFactory,可以拿到BeanFactory这个属性。

public class TestBeanFactoryAware implements BeanFactoryAware {      
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("[TestBeanFactoryAware] " + beanFactory.getBean(TestBeanFactoryAware.class).getClass().getSimpleName());
}
}

可以在bean实例化之后, 初始化之前, 拿到beanFactory, 然后对bean进行特殊化的定制, 或者将beanFactory拿到进行缓存, 日后使用。

8.ApplicationContextAwareProcessor

​org.springframework.context.support.ApplicationContextAwareProcessor​

private void invokeAwareInterfaces(Object bean) {
if (bean instanceof EnvironmentAware) {
((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
}
if (bean instanceof EmbeddedValueResolverAware) {
((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
}
if (bean instanceof ResourceLoaderAware) {
((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
}
if (bean instanceof ApplicationEventPublisherAware) {
((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
}
if (bean instanceof MessageSourceAware) {
((MessageSourceAware) bean).setMessageSource(this.applicationContext);
}
if (bean instanceof ApplicationStartupAware) {
((ApplicationStartupAware) bean).setApplicationStartup(this.applicationContext.getApplicationStartup());
}
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
}
}

6个扩展点: EnvironmentAware, EmbeddedValueResolverAware, ResourceLoaderAware, ApplicationEventPublisherAware, MessageSourceAware, ApplicationContextAware, ApplicationStartupAware

9.BeanNameAware

​org.springframework.beans.factory.BeanNameAware​

public class NormalBeanA implements BeanNameAware{      
public NormalBeanA() {
System.out.println("NormalBean constructor");
}

@Override
public void setBeanName(String name) {
System.out.println("[BeanNameAware] " + name);
}
}

触发点为bean的初始化之前, ​​postProcessBeforeInitialization​​方法之前, 可以通过在初始化bean之前拿到spring容器中注册的的beanName, 修改beanName。

10.@PostConstruct

​javax.annotation.PostConstruct​

public class NormalBeanA {      
public NormalBeanA() {
System.out.println("NormalBean constructor");
}

@PostConstruct
public void init(){
System.out.println("[PostConstruct] NormalBeanA");
}
}

触发点是在postProcessBeforeInitialization之后,InitializingBean.afterPropertiesSet之前。

11.InitializingBean

​org.springframework.beans.factory.InitializingBean​

初始化bean, 在方法​​postProcessAfterInitialization​​之前实现。

public class NormalBeanA implements InitializingBean{      
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("[InitializingBean] NormalBeanA");
}
}

进行系统启动的时候一些业务指标的初始化工作

12.FactoryBean

​org.springframework.beans.factory.FactoryBean​

工厂Bean, Spring提供了70多个实现, 隐藏了复杂的bean的细节, 给上层提供了便利

public class TestFactoryBean implements FactoryBean<TestFactoryBean.TestFactoryInnerBean> {      

@Override
public TestFactoryBean.TestFactoryInnerBean getObject() throws Exception {
System.out.println("[FactoryBean] getObject");
return new TestFactoryBean.TestFactoryInnerBean();
}

@Override
public Class<?> getObjectType() {
return TestFactoryBean.TestFactoryInnerBean.class;
}

@Override
public boolean isSingleton() {
return true;
}

public static class TestFactoryInnerBean{

}
}

可以通过这个类, 实例化bean作为一个代理, 比如为该对象的所以方法做一个拦截, 输出一个日志信息。

13.SmartInitializingSingleton

​org.springframework.beans.factory.SmartInitializingSingleton​

  • afterSingletonsInstantiated: 在spring容器管理的所有单例对象(非懒加载对象)初始化完成之后调用的回调接口。在​​postProcessAfterInitialization​​之后执行。
public class TestSmartInitializingSingleton implements SmartInitializingSingleton {      
@Override
public void afterSingletonsInstantiated() {
System.out.println("[TestSmartInitializingSingleton]");
}
}

可以对于所有单例对象初始化后, 做出一些业务处理

14.CommandLineRunner

​org.springframework.boot.CommandLineRunner​

run方法在触发时机为整个项目启动完毕后,自动执行。如果有多个CommandLineRunner,可以利用@Order来进行排序。

public class TestCommandLineRunner implements CommandLineRunner {      

@Override
public void run(String... args) throws Exception {
System.out.println("[TestCommandLineRunner]");
}
}

15.DisposableBean

​org.springframework.beans.factory.DisposableBean​

  • destroy: 对象销毁时执行。
public class NormalBeanA implements DisposableBean {      
@Override
public void destroy() throws Exception {
System.out.println("[DisposableBean] NormalBeanA");
}
}

16.ApplicationListener

​org.springframework.context.ApplicationListener​

可以监控某个事件, spring内部有内置事件, 可以利用内置事件的监听器达到和前面一些触发点大致相同的事情。

  1. ContextRefreshedEvent: ApplicationContext 被初始化或刷新时,该事件被发布。这也可以在ConfigurableApplicationContext接口中使用 refresh()方法来发生。
  2. ContextStartedEvent: ConfigurableApplicationContext.started()启动ApplicationContext, 发布事件。
  3. ContextStoppedEvent: ConfigurableApplicationContext.stopped()停止ApplicationContext, 发布事件。
  4. ContextClosedEvent: ConfigurableApplicationContext.closed()关闭ApplicationContext, 发布事件。
  5. RequestHandledEvent: web-specific 事件, 告诉所有Bean Http 请求已经被服务。只能应用于使用DispatcherServlet的Web应用。当Spring处理用户请求结束后,系统会自动触发该事件。