几个强大的Spring Boot扩展点

文摘   2024-10-30 08:00   新疆  

最新实战案例锦集:《Spring Boot3实战案例合集》持续更新,每天至少更新一篇文章,订阅后将赠送文章最后展示的所有MD文档(学习笔记)。

环境:SpringBoot3.2.5



1. 简介

Spring Boot 提供了非常多的强大扩展点,通过这些扩展点可以满足我们在不同场景下的定制化需求。开发者可以通过这些扩展点在应用生命周期的关键时刻介入,从而实现特定的功能或逻辑。下面是本篇文章将要介绍的扩展点:

  • AutoConfigurationImportFilter

    用于限制自动配置类。

  • ApplicationContextFactory

    用于创建 SpringApplication 使用的 ConfigurableApplicationContext 的策略接口。创建的上下文应以默认形式返回,由 SpringApplication 负责配置和刷新上下文。

  • SpringApplicationRunListener

    通过该接口,我们可以自定义Spring Boot在启动过程中每个阶段需要执行的事件监听动作。

  • ApplicationContextInitializer

    该接口在Spring容器执行刷新动作执行执行,在refresh你可以对容器进行相应的操作。

接下来,我们将详细的介绍上面几个强大的容器扩展点的应用。

2. 实战案例

2.1 AutoConfigurationImportFilter

默认情况下,Spring Boot提供了3个该接口的实现,如下:

  • OnBeanCondition

    该实现用来检查当前容器中是否存在相应的Bean。

  • OnClassCondition

    检查当前CLASSPATH下是否有相应的类。

  • OnWebApplicationCondition

    检查当前Spring运行的环境:SERVLET,REACTIVE。

我们可以通过自定义实现自己的检查,如下示例:

public class PackClassCondition implements AutoConfigurationImportFilter, EnvironmentAware {
private Environment environment ; @Override public boolean[] match(String[] autoConfigurationClasses, AutoConfigurationMetadata autoConfigurationMetadata) { boolean[] matchs = new boolean[autoConfigurationClasses.length] ; for (int i = 0, len = matchs.length; i < len; i++) { if (autoConfigurationClasses[i] != null && autoConfigurationClasses[i].equals(PackAutoConfiguration.class.getName())) { Boolean ret = this.environment.getProperty("pack.app.enabled", Boolean.class, false) ; matchs[i] = ret ; } else { matchs[i] = true ; } } return matchs ; } @Override public void setEnvironment(Environment environment) { this.environment = environment ; }}

在该实现中,我们判断了当前的类是否是PackAutoConfiguration,如果是则判断当前配置的 pack.app.enabled 是否为true,只有为true该自动配置才会生效。

接下来,需要在META-INF/spring.factories中进行注册

org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\com.pack.extension.autoImportfilter.PackClassCondition

通常情况,我们是不需要自己实现该接口的,Spring Boot提供的有关条件注解基本上是能够满足我们的需求的。

2.2 ApplicationContextFactory

该接口用来创建当前Spring Boot所需的ApplicationContext容器。这里你可以根据当前的环境或者其它一些自定义的条件进行容器的创建。默认提供了2种环境下的容器创建:分别是,SERVLET,REACTIVE。如下示例:

public class PackApplicationContextFactory implements ApplicationContextFactory {
@Override public ConfigurableApplicationContext create(WebApplicationType webApplicationType) { return (webApplicationType != WebApplicationType.SERVLET) ? null : createContext(); }
private ConfigurableApplicationContext createContext() { System.err.println("使用自定义容器...") ; return new PackApplicationContext(); } public static class PackApplicationContext extends AnnotationConfigServletWebServerApplicationContext{
@Override protected void prepareRefresh() { System.err.println("准备执行容器核心方法refresh") ; super.prepareRefresh(); } }}

这里我们自定义了ApplicationContext容器,不过仅仅是重写了prepareRefresh方法,打印了一段话。

在META-INF/spring.factories中进行注册

org.springframework.boot.ApplicationContextFactory=\com.pack.extension.contextfactory.PackApplicationContextFactory

启动应用见看到到如下信息

使用了我们自定义的ApplicationContext容器。

2.3 SpringApplicationRunListener

该接口中定义了如下Spring Boot在启动过程中不同阶段将会触发的事件

public interface SpringApplicationRunListener {
default void starting(ConfigurableBootstrapContext bootstrapContext) {  }  default void environmentPrepared(   ConfigurableBootstrapContext bootstrapContext,   ConfigurableEnvironment environment) {  } default void contextPrepared(ConfigurableApplicationContext context) {  } default void contextLoaded(ConfigurableApplicationContext context) {  } default void started(ConfigurableApplicationContext context, Duration timeTaken) {  } default void ready(ConfigurableApplicationContext context, Duration timeTaken) {  } default void failed(ConfigurableApplicationContext context, Throwable exception) {  }}

Spring Boot默认提供了 EventPublishingRunListener 实现,在该实现中针对不同的阶段都会触发相应的事件。如下自定义实现:

public class PackSpringApplicationRunListener implements SpringApplicationRunListener, Ordered {
@Override public int getOrder() { return 1 ; }
@Override public void contextPrepared(ConfigurableApplicationContext context) { System.err.println("ApplicationContext 创建并准备好, 还没有开始调用refresh方法") ; }
// 上下文已经被刷新,并且应用程序已经启动,但是 *Runners 尚未被调用。 @Override public void started(ConfigurableApplicationContext context, Duration timeTaken) { System.err.printf("上下文已经被刷新,并且应用程序已经启动,但 *Runners 尚未被调用, 应用程序启动所花费时间: %dms%n", timeTaken.toMillisPart()) ; } }

这里仅仅是打印了一段文字,演示效果

在META-INF/spring.factories中进行注册

org.springframework.boot.SpringApplicationRunListener=\com.pack.extension.eventpublisher.PackSpringApplicationRunListener

启动服务

注意:在自定义实现的SpringApplicationRunListener构造函数中,我们可以添加2个参数,分别是为

  • SpringApplication

    该参数值就是当前main函数启动的那个实例。

  • String[] args

    该数组参数是main函数启动时添加的命令行参数。

     

如下示例:

private SpringApplication app ;private final String[] args ;
public PackSpringApplicationRunListener(SpringApplication app, String[] args) { this.app = app ; this.args = args ; System.err.printf("%s%s%n", app, Arrays.toString(this.args)) ;}

启动应用是设置如下:

java -jar App.jar --pack.title=xxxooo, --pack.version=1.0.0

输出结果

org.SpringApplication@78ac1102[--pack.title=xxxooo,, --pack.version=1.0.0]

注:目前只支持这2中数据类型。

2.4 ApplicationContextInitializer

该接口可以在Spring容器在正式刷新执行执行,此时我们可以对容器进行相应的配置管理。

public class PackApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override public void initialize(ConfigurableApplicationContext context) { context.addApplicationListener(null) ; context.addBeanFactoryPostProcessor(null) ; context.getEnvironment().getConversionService().addConverter(null) ; // ...  }}

在该示例中,我们可以像容器中注册ApplicationListener事件监听器、BeanFactoryPostProcessor 容器后处理器,给当前Environment添加类型转换器。

在META-INF/spring.factories中进行注册

org.springframework.context.ApplicationContextInitializer=\com.pack.extension.contextinitializer.PackApplicationContextInitializer

以上是本篇文章的全部内容,如对你有帮助帮忙点赞+转发+收藏

推荐文章

性能提升!@Async与CompletableFuture优雅应用

进阶!@ConfigurationProperties注解高级用法你知道吗?

手写@RefreshScope,很简单嘛!

掌握这3个Spring Boot技能,实时监控Controller接口性能

Spring强大的URI操作工具类太方便了

Spring创建AOP代理并非只有@Aspect一种方式

使用Vault保护SpringBoot配置文件中的敏感数据

SpringBoot整合Flink CDC,实时追踪数据变动,无缝同步至Redis

SpringBoot一个注解轻松实现多版本Rest API接口控制

SpringBoot优雅地定制JSON响应数据

Spring6.2新特性@Fallback候选Bean

Spring6.2这几个新功能及优化太强了

Spring全家桶实战案例源码
spring, springboot, springcloud 案例开发详解
 最新文章