聊聊SpringBoot中10个扩展点的定义以及执行时机

https://juejin.cn/post/6999603401239576583


highlight: androidstudio

前言 :
Spring 的扩展点 是Spring易扩展的一个重要体现,熟悉这些扩展点的定义方式,以及其调用时机,可以在我们开发过程中游刃有余,进行各种骚操作。我个人觉得熟悉他们 并知道其原理,是非常有必要的,今天我们就一个个来看下。

本文总结出10个扩展点,如有遗漏,欢迎补充~

  • 本文示例代码均已经上传到github 地址: https://github.com/598572/xzll/tree/main/study-admin/study-admin-service/src/main/java/com/xzll/test/point

扩展点1

实现 ApplicationContextInitializer的initialize方法

  • 时机 : spring容器还没被刷新之前 准备阶段 this.prepareContext(context, environment, listeners, applicationArguments, printedBanner); 此时所有的配置文件都已经加载
/**
 * ApplicationContextInitializer扩展点演示 时机: spring容器还没被刷新之前
 *
 * <p>
 * 因为这时候spring容器还没被刷新,所以想要自己的扩展的生效,有以下三种方式:
 * <p>
 * 1.在启动类中用springApplication.addInitializers(new ApplicationContextInitializerPoint())语句加入
 * 2.配置文件配置context.initializer.classes=com.xzll.test.ApplicationContextInitializerPoint
 * 3.Spring SPI扩展,在spring.factories中加入org.springframework.context.ApplicationContextInitializer=com.xzll.test.ApplicationContextInitializerPoint
 * <p>
 * //TODO 目前我试了三种方式 只有第二种方式可以输出该类的打印语句 ,1和2都没有输出打印语句 目前不知原因为何。留作以后研究吧
 *
 * 这是整个spring容器在刷新之前初始化ConfigurableApplicationContext的回调接口,简单来说,就是在容器刷新之前调用此类的initialize方法。
 * 这个点允许被用户自己扩展。用户可以在整个spring容器还没被初始化之前做一些事情。
 * 可以想到的场景可能为,在最开始激活一些配置,或者利用这时候class还没被类加载器加载的时机,进行动态字节码注入等操作。
 */
public class ApplicationContextInitializerPoint implements ApplicationContextInitializer<ConfigurableApplicationContext> {
   

   @Override
   public void initialize(ConfigurableApplicationContext applicationContext) {
   

      // System.out.println("applicationContext: "+ JSON.toJSONString(applicationContext));
      // 注意这里引入不了FastJson 会报错 AnnotationConfigApplicationContext has not been refreshed yet  ; AnnotationConfigApplicationContext 尚未刷新
      // 详见: https://stackoverflow.com/questions/28404817/annotationconfigapplicationcontext-has-not-been-refreshed-yet-whats-wrong
      System.out.println("------------ApplicationContextInitializerPoint # initialize 开始-------------");
      System.out.println("[ApplicationContextInitializer扩展点演示] # initialize:  " + applicationContext.toString());
      System.out.println("BeanDefinitionCount count: " + applicationContext.getBeanDefinitionCount());
      ConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory();
      Iterator<String> beanNamesIterator = beanFactory.getBeanNamesIterator();
      beanNamesIterator.forEachRemaining(System.out::println);
      System.out.println("时机: "+ "run 方法中的 this.prepareContext(); 的时候");
      System.out.println("-------------ApplicationContextInitializerPoint # initialize 结束------------");
      System.out.println();

   }

   /*

   private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
        context.setEnvironment(environment);
        this.postProcessApplicationContext(context);
        this.applyInitializers(context);
        listeners.contextPrepared(context);
        if (this.logStartupInfo) {
            this.logStartupInfo(context.getParent() == null);
            this.logStartupProfileInfo(context);
        }

        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
        if (printedBanner != null) {
            beanFactory.registerSingleton("springBootBanner", printedBanner);
        }

        if (beanFactory instanceof DefaultListableBeanFactory) {
            ((DefaultListableBeanFactory)beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
        }

        Set<Object> sources = this.getAllSources();
        Assert.notEmpty(sources, "Sources must not be empty");
        this.load(context, sources.toArray(new Object[0]));
        listeners.contextLoaded(context);
    }


     protected void applyInitializers(ConfigurableApplicationContext context) {
        Iterator var2 = this.getInitializers().iterator();

        while(var2.hasNext()) {
            ApplicationContextInitializer initializer = (ApplicationContextInitializer)var2.next();
            Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(), ApplicationContextInitializer.class);
            Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
            initializer.initialize(context);// todo 此处回调 initialize 方法
        }

    }

    */
}

扩展点2

实现 BeanDefinitionRegistryPostProcessor或BeanFactoryPostProcessor 的 postProcessBeanDefinitionRegistry 和 postProcessBeanFactory方法

  • 时机: refresh()的 this.invokeBeanFactoryPostProcessors(beanFactory);此时此bean的定义信息 都已经加载完毕 但是还没到实例化以及初始化阶段
@Component
public class BeanDefinitionRegistryPostProcessorPoint implements BeanDefinitionRegistryPostProcessor {
   

   @Override
   public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
   
      System.out.println("-----------------------[BeanDefinitionRegistryPostProcessor扩展点演示] # postProcessBeanDefinitionRegistry 开始--------------------------------------");
      System.out.println("[BeanDefinitionRegistryPostProcessor扩展点演示] # postProcessBeanDefinitionRegistry");
      System.out.println("时机: refresh()的 this.invokeBeanFactoryPostProcessors(beanFactory); 方法中执行; " +
            "此时 bean的定义信息 都已经加载完毕 但是还没到实例化以及初始化阶段");
      System.out.println("-----------------------[BeanDefinitionRegistryPostProcessor扩展点演示] # postProcessBeanDefinitionRegistry 结束--------------------------------------");
      System.out.println();
   }

   @Override
   public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
   
      System.out.println("-----------------------[BeanDefinitionRegistryPostProcessor扩展点演示] # postProcessBeanFactory 开始--------------------------------------");
      System.out.println("[BeanDefinitionRegistryPostProcessor扩展点演示] # postProcessBeanFactory");
      System.out.println("时机: refresh()的 this.invokeBeanFactoryPostProcessors(beanFactory); 方法中执行; " +
            "此时 bean的定义信息 都已经加载完毕 但是还没到实例化以及初始化阶段");
      System.out.println("-----------------------[BeanDefinitionRegistryPostProcessor扩展点演示] # postProcessBeanFactory 结束--------------------------------------");
      System.out.println();
   }
}
@Component
public class BeanFactoryPostProcessorPoint implements BeanFactoryPostProcessor {
   
   @Override
   public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
   
      System.out.println("-----------------------[BeanFactoryPostProcessor扩展点演示] # postProcessBeanFactory 开始--------------------------------------");
      System.out.println("[BeanFactoryPostProcessor扩展点演示] # postProcessBeanFactory");
      System.out.println("时机: refresh()的 this.invokeBeanFactoryPostProcessors(beanFactory); 方法中执行; " +
            "此时 bean的定义信息 都已经加载完毕 但是还没到实例化以及初始化阶段");
      System.out.println("-----------------------[BeanFactoryPostProcessor扩展点演示] # postProcessBeanFactory 结束--------------------------------------");
      System.out.println();
   }
}

扩展点3

实现 BeanPostProcessor 的 postProcessBeforeInitialization 或postProcessAfterInitialization方法

时机: bean在初始化之前(postProcessBeforeInitialization) 和初始化之后(postProcessAfterInitialization),注意 初始化前说明其肯定已经实例化了

@Configuration
public class BeanPostProcessPoint implements BeanPostProcessor {
   


   public BeanPostProcessPoint() {
   
      System.out.println();
      System.out.println("################## BeanPostProcessPoint 的构造方法 ##################");
      System.out.println();
   }

   /**
    * bean初始化之前
    *
    * @param bean
    * @param beanName
    * @return
    * @throws BeansException
    */
   @Override
   public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
   
      /**
       * 可以根据需要在这里进行某个bean的扩展
       */
      if (bean instanceof TestController) {
   
         System.out.println("-----------------------[BeanPostProcessPoint]  扩展点演示 # postProcessBeforeInitialization  开始--------------------------------------");
         System.out.println("[BeanPostProcessPoint]  扩展点演示 # postProcessBeforeInitialization , crurrentBeanName: " + beanName);
  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值