天天看點

SpringBoot 擴充性接口

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​

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​

  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處理使用者請求結束後,系統會自動觸發該事件。