SpringBoot 的启动扩展点 ApplicationContextInitializer

2022-08-14 17:09:56   最后更新: 2022-08-14 17:09:56   访问数量:85




 

此前的文章中,我们详细介绍了 Spring 预留的六个可以用来扩展代码的扩展点,从而让我们能够在 Spring 的启动阶段添加我们需要的业务启动代码:

 

自定义 SpringBoot 启动方法的六种方式(上)

 

自定义 SpringBoot 启动方法的六种方式(下)

 

事实上,Spring 的扩展点还有很多,只是通常如果我们仅仅是添加业务启动代码,或是对运行参数进行初始化解析,使用上述六个扩展点就已经可以满足需求。

 

但是,如果我们想要从根本上改变一些 Spring 的默认行为,例如修改 Context 中的属性,或者要改变 bean 的创建加载行为,这时,我们就必须在 SpringBoot 生命周期的最早期进行扩展。

 

SpringBoot 为我们预留了这样的扩展点,它就是本文将要介绍的 ApplicationContextInitializer。

 

 

 

 

SpringBoot 在 Spring 的基础上,遵循约定大于配置原则,加入了许许多多自动装配的机制。让我们在给别人提供组件时,只需要按照 SpringBoot 的规范实现我们自己的扩展,别人无需任何配置就可以自动装配我们的组件。ApplicationContextInitializer 就是可以被这样自动装配的扩展点。

 

SpringBoot 会在完成 ConfigurableApplicationContext 的构建后,在容器刷新之前,自动调用已经被装配进 SpringBoot 容器的 ApplicationContextInitializer 接口实现类,执行它的 initialize 方法。

 

ApplicationContextInitializer 接口的定义如下:

 

public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> { void initialize(C var1); }

 

 

如果这个接口有多个实现类,SpringBoot 支持通过 @Order 注解或实现 Ordered 接口指定每个实现类的执行优先级。

 

 

如果我们实现了上述 ApplicationContextInitializer 接口,如何将我们的实现类添加到 SpringBoot 的启动中呢?有三种方法。

 

3.1 在 main 方法中调用

 

通过 SpringApplication 对象的 addInitializers 方法,可以添加多个 ApplicationContextInitializer 实现类:

 

@SpringBootApplication public class MySpringBootApplication { public static void main(String[] args) { SpringApplication application = new SpringApplication(MySpringBootApplication.class); application.addInitializers(new MyApplicationContextInitializer()); application.run(args); } }

 

 

3.2 在 classpath 下的配置文件中配置

 

SpringBoot 启动时,会扫描 classpath,寻找 application.properties 配置,来找到启动过程中需要调用的相关组件。

 

在这个配置文件中,加入 ApplicationContextInitializer 实现类的配置,就可以实现让 SpringBoot 自动加载该实现类。

 

context.initializer.classes=org.springframework.boot.demo.common.MyApplicationContextInitializer

 

 

3.3 SpringBoot 的 SPI 扩展 -- META-INF/spring.factories 中配置

 

在 classpath 下的 META-INF/spring.factories 中配置相应的实现类也同样可以配置 ApplicationContextInitializer 实现类的自动加载和启动:

 

org.springframework.context.ApplicationContextInitializer=org.springframework.boot.demo.common.MyApplicationContextInitializer

 

 

 

在 SpringBoot 中,创建 bean 有多种方法:

 

  1. 通过 xml bean 标签描述的方法;
  2. @Bean 注解的方法;
  3. 通过 @Component、@Service、@Controler、@Repository 注解的类;
  4. 通过 @Import 注解;
  5. 实现 ImportSelector、ImportBeanDefinitionRegistrar、EnableImportSelector 接口;
  6. 通过 beanFactory 手动注入。

 

这些方式我们已经很熟悉了,但有时,我们希望完全自己构造出一个 bean 对象,并且由于它受到其它 bean 的依赖,需要在启动最初的阶段被加载到 SpringBoot 的上下文环境中,这时,通过 ApplicationContextInitializer 来实现就是一个很好的选择。

 

下面的例子展示了通过 ApplicationContextInitializer 的实现类创建 bean:

 

public class BootInitializer implements ApplicationContextInitializer<GenericApplicationContext> { @Override public void initialize(GenericApplicationContext genericApplicationContext) { String beanName = "BootInitializeBean"; Object beanObject = generateBeanObject(beanName); genericApplicationContext.registerBean(beanName, beanObject.getClass(), (Supplier) () -> beanObject, bd -> { bd.setAutowireCandidate(false); bd.setLazyInit(true); }); } }

 

 

在这个例子中,调用了回调参数 GenericApplicationContext 对象的 registerBean 方法,指定了 bean 的 name、类型、对象以及 bean 属性。

 

值得提的是第四个参数,该参数是可选的,它是用来指定 bean 属性的 BeanDefinitionCustomizer 接口实现。

 

当然了,这只是一个例子,除此以外,ApplicationContextInitializer 还有多种用途,例如将 beanFactory 替换成你自己实现的对象,来实现你想要的独特的 bean 加载方式等等。

 

 

 

 

欢迎关注微信公众号,以技术为主,涉及历史、人文等多领域的学习与感悟,每周三到七篇推文,只有全部原创,只有干货没有鸡汤

 

Spring 从入门到实战






java      技术贴      spring      springboot      applicationcontextinitializer     


京ICP备2021035038号