SpringBoot 的启动扩展点 ApplicationContextInitializer

用户3147702 2022-09-23 09:26:47 阅读数:165

SpringBoot扩展启动applicationcontextinitializer

1. 引言

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

添加 SpringBoot 自定义启动代码的六种方式(上)

添加 SpringBoot 自定义启动代码的六种方式(下)

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

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

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

2. ApplicationContextInitializer

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

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

ApplicationContextInitializer 接口的定义如下:

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

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

3. 添加启动的三种方式

如果我们实现了上述 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

4. 实例:利用 ApplicationContextInitializer 实现 bean 的手动加载

在 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 加载方式等等。

版权声明:本文为[用户3147702]所创,转载请带上原文链接,感谢。 https://cloud.tencent.com/developer/article/2118810