详解Spring Framework提供的扩展点:ApplicationContextInitializer应用上下文初始化器,以及它在SpringBoot中的应用【享学Spring】(下)

简介: 详解Spring Framework提供的扩展点:ApplicationContextInitializer应用上下文初始化器,以及它在SpringBoot中的应用【享学Spring】(下)

SpringBoot中ApplicationContextInitializer的使用


思考良久,最终还是决定把该初始化器在SpringBoot中的应用也在此处一并说明了(毕竟这块的使用还是比较简单的,所以放一起吧)


熟悉SpringBoot的小伙伴应该知道:它里面大量的使用到了Spring容器上下文启动的相关回调机制:比如SPI、事件/监听、启动器等等。


ApplicationContextInitializer是在springboot启动过程(refresh方法前)调用。提取部分源码参考如下:

public class SpringApplication {
  // 对象初始化的时候 会从spring.factories里拿出来
  private void initialize(Object[] sources) {
    ...
    setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
    ...
  }
  public ConfigurableApplicationContext run(String... args) {
    ...
      prepareContext(context, environment, listeners, applicationArguments, printedBanner);
    ...
  }
  private void prepareContext(ConfigurableApplicationContext context,
      ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
      ApplicationArguments applicationArguments, Banner printedBanner) {
    ...
    applyInitializers(context);
    ...
  }
  // 执行处  把所有的遍历执行(已经排序)getInitializers里会根据order进行排序
  protected void applyInitializers(ConfigurableApplicationContext context) {
    for (ApplicationContextInitializer initializer : getInitializers()) {
      Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(
          initializer.getClass(), ApplicationContextInitializer.class);
      Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
      initializer.initialize(context);
    }
  }
}


了解了SpringBoot加载、执行ApplicationContextInitializer的过程,就可以很容易总结出在SpringBoot中自定义使用ApplicationContextInitializer的三种方式:


请注意在SpringBoot中自定义和在Spring Framework中自定义的步骤区别~


SpringBoot中自定义ApplicationContextInitializer的三种方式

spring.factories方式(官方就是这么用的,推荐)


不解释


application.properties添加配置方式

对于这种方式是通过DelegatingApplicationContextInitializer这个初始化类中的initialize方法获取到application.properties中的context.initializer.classes实现类的


所以只需要将实现了ApplicationContextInitializer的类添加到application.properties即可。示例如下:

context.initializer.classes=你的实现类全类名


API方式addInitializers()方法添加


形如:

  public static void main(String[] args) {
    //type01
    SpringApplication springApplication = new SpringApplication(Application.class);
    // 添加进去
    springApplication.addInitializers(new Demo01ApplicationContextInitializer());
    springApplication.run(args);
    //SpringApplication.run(InitializerDemoApplication.class,args);
  }


虽然三种方式都可以,但个人比较推荐的方式为通过spring.factories方式配置


SpringBoot内置的一些ApplicationContextInitializer


下面列出了一个使用缺省配置的Springboot web应用默认所使用到的ApplicationContextInitializer实现们:


DelegatingApplicationContextInitializer

使用环境属性context.initializer.classes指定的初始化器(initializers)进行初始化工作,如果没有指定则什么都不做。


通过它使得我们可以把自定义实现类配置在application.properties里成为了可能


ContextIdApplicationContextInitializer


设置Spring应用上下文的ID,会参照环境属性。至于Id设置为啥值会参考环境属性:

spring.application.name

vcap.application.name

spring.config.name

spring.application.index

vcap.application.instance_index


如果这些属性都没有,ID使用application。


ConfigurationWarningsApplicationContextInitializer

对于一般配置错误在日志中作出警告


ServerPortInfoApplicationContextInitializer

将内置servlet容器实际使用的监听端口写入到Environment环境属性中。这样属性local.server.port就可以直接通过@Value注入到测试中,或者通过环境属性Environment获取。


SharedMetadataReaderFactoryContextInitializer


创建一个SpringBoot和ConfigurationClassPostProcessor共用的CachingMetadataReaderFactory对象。实现类为:ConcurrentReferenceCachingMetadataReaderFactory


ConditionEvaluationReportLoggingListener

将ConditionEvaluationReport写入日志。


以上都是SpringBoot内置的上文启动器,可见Spring留出的这个钩子,被SpringBoot发扬光大了。

实际上不仅于此,SpringBoot对Spring Framework的事件监听机制也都有大量的应用~


总结


ApplicationContextInitializer是Spring留出来允许我们在上下文刷新之前做自定义操作的钩子,若我们有需求想要深度整合Spring上下文,借助它不乏是一个非常好的实现。


随便浏览一下SpringBoot的源码可知,它对Spring特征特性的使用,均是非常的流畅且深度整合的。所以说SpringBoot易学难精的最大拦路虎:其实是对Spring Framework系统性的把握~


Tips:spring-test包里有个注解org.springframework.test.context.ContextConfiguration它有个属性可以指定ApplicationContextInitializer辅助集成测试时候的自定义对上下文进行预处理~

相关文章
|
23小时前
|
监控 Java 应用服务中间件
spring和springboot的区别
spring和springboot的区别
20 1
|
23小时前
|
Java 开发者 Spring
Spring Framework 中的 @Autowired 注解:概念与使用方法
【4月更文挑战第20天】在Spring Framework中,@Autowired 注解是实现依赖注入(Dependency Injection, DI)的一种非常强大的工具。通过使用 @Autowired,开发者可以减少代码中的引用绑定,提高模块间的解耦能力
33 6
|
23小时前
|
SQL Java 数据库连接
Springboot框架整合Spring JDBC操作数据
JDBC是Java数据库连接API,用于执行SQL并访问多种关系数据库。它包括一系列Java类和接口,用于建立数据库连接、创建数据库操作对象、定义SQL语句、执行操作并处理结果集。直接使用JDBC涉及七个步骤,包括加载驱动、建立连接、创建对象、定义SQL、执行操作、处理结果和关闭资源。Spring Boot的`spring-boot-starter-jdbc`简化了这些步骤,提供了一个在Spring生态中更便捷使用JDBC的封装。集成Spring JDBC需要添加相关依赖,配置数据库连接信息,并通过JdbcTemplate进行数据库操作,如插入、更新、删除和查询。
|
23小时前
|
SQL Java 数据库连接
Springboot框架整合Spring Data JPA操作数据
Spring Data JPA是Spring基于ORM和JPA规范封装的框架,简化了数据库操作,提供增删改查等接口,并可通过方法名自动生成查询。集成到Spring Boot需添加相关依赖并配置数据库连接和JPA设置。基础用法包括定义实体类和Repository接口,通过Repository接口可直接进行数据操作。此外,JPA支持关键字查询,如通过`findByAuthor`自动转换为SQL的`WHERE author=?`查询。
|
23小时前
|
Java
SpringBoot 项目启动初始化一个Map对象到内存
SpringBoot 项目启动初始化一个Map对象到内存
|
23小时前
|
Java Maven Docker
0.07 秒启动一个 SpringBoot 项目!Spring Native 很强!!
0.07 秒启动一个 SpringBoot 项目!Spring Native 很强!!
26 2
|
23小时前
|
前端开发 Java Spring
Spring Framework五大功能模块
Spring Framework五大功能模块
|
23小时前
|
Java Maven 数据库
Spring Boot Starter: 快速简明地创建Spring应用
Spring Boot Starter: 快速简明地创建Spring应用
|
23小时前
|
Java Nacos 开发者
Java从入门到精通:4.2.1学习新技术与框架——以Spring Boot和Spring Cloud Alibaba为例
Java从入门到精通:4.2.1学习新技术与框架——以Spring Boot和Spring Cloud Alibaba为例
|
23小时前
|
设计模式 Java 数据库连接
Spring Framework 6 中的设计模式
Spring Framework 6 中的设计模式
22 1