Springboot扩展点之ApplicationContextInitializer

文章详细介绍了Springboot的扩展点ApplicationContextInitializer的工作原理、实现方式和常见内置实现类,包括通过spring.factories、application.properties和代码注册实现,以及初始化和执行时机。此外,还讨论了其他相关扩展点如BeanFactoryPostProcessor和BeanPostProcessor,强调理解这些扩展点对于深入掌握Springboot的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Springboot扩展点系列实现方式、工作原理集合:

Springboot扩展点之ApplicationContextInitializer

Springboot扩展点之BeanFactoryPostProcessor

Springboot扩展点之BeanDefinitionRegistryPostProcessor

Springboot扩展点之BeanPostProcessor

Springboot扩展点之InstantiationAwareBeanPostProcessor

Springboot扩展点之SmartInstantiationAwareBeanPostProcessor

Springboot扩展点之ApplicationContextAwareProcessor

Springboot扩展点之@PostConstruct

Springboot扩展点之InitializingBean

Springboot扩展点之SmartInitializingSingleton

Springboot扩展点之CommandLineRunner和ApplicationRunner

Springboot扩展点之FactoryBean

Springboot扩展点之DisposableBean

Springboot扩展点系列之终结篇:Bean的生命周期


前言        

        一提到Spring、Springoboot,很多人马上就会想到依赖注入、控制反转、自动装配、约定大于配置、使开发变得简单等等。但是如果仅仅会使用Springboot、SpringMVC完成一些增删改查,解决一些bug,那么实际上你并没有真的懂Spring、Springboot。Spring的核心是容器,Springboot更是封装了Spring,把复杂隐藏在内部,让其在使用上更简单,同时又预留了很多的扩展。所以我认为学会Springboot的简单使用只是一个开始,对业务开发更有参考和学习意义的是Springboot如何把复杂变得简单、预留的扩展接口又是如何使用的。

1. ApplicationContextInitializer的功能作用

  1. 在Spring容器初始化开始的时候,ApplicationContextInitializer接口的所有实现在类会被实例化;
  2. 在Spring容器刷新前,所有实现类的org.springframework.context.ApplicationContextInitializer#initialize方法会被调用,initialize方法的形参类型是ConfigurableApplicationContext,因此可以认为ApplicationContextInitializer实际上是Spring容器初始化前ConfigurableApplicationContext的回调接口,可以对上下文环境作一些操作,如运行环境属性注册、激活配置文件等
public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> {

   /**
    * Initialize the given application context.
    * @param applicationContext the application to configure
    */
   void initialize(C applicationContext);

}

2. 三种实现方式

        下面通过一个具体实现类实现ApplicationContextInitializer接口,来分享一下其具体的实现方式。Springboot的扩展点ApplicationContextInitializer接口的实现主要分为两步:

1、实现ApplicationContextInitializer接口; 

        MyApplicationContextInitializer实现ApplicationContextInitializer接口,并打印一下系统相关属性的key、value

public class MyApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        Map<String, Object> systemProperties = applicationContext.getEnvironment().getSystemProperties();
        System.out.println("---------------start------------------");
        systemProperties.forEach((key,value)->{
            System.out.println("key:"+key+",value:"+value);
        }); System.out.println("---------------end------------------");
    }
}

2、把实现类注册到Spring容器中

把实现类MyApplicationContextInitializer注册到Spring容器中,主要有三种方式:

2.1 spring.factories

        在resources目录新建/META-INFI/spring.factories文件,并预置以下内容,即可完成自定义MyApplicationContextInitializer的注册;

org.springframework.context.ApplicationContextInitializer=com.fanfu.config.MyApplicationContextInitializer

2.2 application.properties

在application.properties文件中预置以下配置内容,即可完成自定义MyApplicationContextInitializer的注册;

context.initializer.classes=com.fanfu.config.MyApplicationContextInitializer

2.3 springApplication.addInitializers()

在springboot的启动类中,使用springApplication.addInitializers(new MyApplicationContextInitializer()),完成自定义MyApplicationContextInitializer的注册;

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

执行结果如下:(user.dir=项目的根目录)

3. 初始化时机

ApplicationContextInitializer接口的实现类的初始化,是在SpringApplication类的构造函数中,即spring容器初始化开始前,先通过 getSpringFactoriesInstances(...)得到所有实现类的集合,然后通过 setInitializers(...)注入到SpringApplication类的initializersn属性中;

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
   this.resourceLoader = resourceLoader;
   Assert.notNull(primarySources, "PrimarySources must not be null");
   this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
   this.webApplicationType = WebApplicationType.deduceFromClasspath();
   setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
   setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
   this.mainApplicationClass = deduceMainApplicationClass();
}

4. 执行时机

ApplicationContextInitializer接口的实现类的执行时机是在org.springframework.boot.SpringApplication#prepareContext-->org.springframework.boot.SpringApplication#applyInitializers中,即spring容器正式刷新前,准备上下文环境时;

  1. getInitializers()得到,SpringApplication类的构造函数中通过 setInitializers(...)注入到SpringApplication类的initializersn属性中的所有ApplicationContextInitializer接口的实现类;
  2. 遍历这些实现类,并调用initialize()方法;
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);
   }
}

5. 内置的实现类

        Springboot内部也有一些内置的实现类,用于辅助Spring相关功能的实现,常见的实现类如下:

5.1 DelegatingApplicationContextInitializer

ApplicationContextInitializer的第二种实现方式(application.properties),在application.properties文件中配置context.initializer.classes=com.fanfu.config.MyApplicationContextInitializer,DelegatingApplicationContextInitializer的作用就是找到application.properties文件中配置的实现类实例化,并执行initialize()方法

5.2 ContextIdApplicationContextInitializer

ContextIdApplicationContextInitializer用于设置 Spring 应用上下文 ID,如果在application.properties中未设置spring.application.name,则默认为“application”

5.3 ConfigurationWarningsApplicationContextInitializer

ConfigurationWarningsApplicationContextInitializer用于报告 Spring 容器的一些常见的错误配置,可以看出,该初始化器为 context 增加了一个 Bean 的后置处理器。这个处理器是在注册 BeanDefinition 实例之后生效的,用于处理注册实例过程中产生的告警信息,其实就是通过日志打印出告警信息。

5.4 ServerPortInfoApplicationContextInitializer

ServerPortInfoApplicationContextInitializer除了实现了ApplicationContextInitializer接口外,还实现了ApplicationListener接口,ServerPortInfoApplicationContextInitializer作用就是把自己作为一个监听器注册到Spring的上下文环境中;

5.5 SharedMetadataReaderFactoryContextInitializer

实例化了一个org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer.CachingMetadataReaderFactoryPostProcessor对象并注册到了Spring的上下文环境中,CachingMetadataReaderFactoryPostProcessor是SharedMetadataReaderFactoryContextInitializer的一个内部类,这里就不具体展开了,有兴趣的小伙伴可以继续跟一下org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer.CachingMetadataReaderFactoryPostProcessor#postProcessBeanDefinitionRegistry方法了解一下具体的内容;

5.6 ConditionEvaluationReportLoggingListener

ConditionEvaluationReportLoggingListener从名字看是一个监听器,实际上不是,其内部类org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener.ConditionEvaluationReportListener才是实际的监听器,而ConditionEvaluationReportLoggingListener的作用就是把内部类ConditionEvaluationReportListener注册到Spring上下文环境中;

6. 总结

通过这篇文章,可以了解到:

第一,在Spring容器被刷新前,可以通过实现ApplicationContextInitializer接口对Spring上下文环境作一些配置或操作;

第二,ApplicationContextInitializer接口的实现方式有三种,可以根据项目需要选择合适的;

第三,了解了ApplicationContextInitializer接口实现类的初始化时机和执行时机,以及Springboot内置的具体实现类,可以学习到spring本身是如何利用扩展接口实现一些功能的,对实际的项目开发具有一定的参考意义。

示例代码地址:凡夫贩夫 / fanfu-web · GitCode(ApplicationContextInitializer分支)

<think>好的,用户想了解在Spring Boot中如何创建和实现自定义扩展点。我需要根据提供的引用内容来整理相关信息。首先,引用[1]提到Spring Boot扩展点和启动顺序图,还有bean加载的过程。这可能涉及到BeanPostProcessor、InitializingBean等接口。引用[2]展示了AOP的使用,比如通过@Aspect和@Component创建切面,但用户的问题是关于扩展点,可能需要更基础的方式。引用[3]提到了InitializingBean的afterPropertiesSet方法和@PostConstruct注解,这些都是bean生命周期中的扩展点。 用户需要具体的实现方式和示例教程。我需要分步骤说明不同的扩展点实现方法。首先想到的是BeanPostProcessor,因为它允许在bean初始化前后插入自定义逻辑。然后,InitializingBean接口和@PostConstruct注解,这两个都是在bean初始化时调用的。还有FactoryBean,可以用来创建复杂的bean。另外,可能还可以提到ApplicationContextInitializer或者Spring Boot的启动监听器,但引用中没有提到这些,可能暂时不涉及。 需要确保每个步骤都有示例代码,比如实现BeanPostProcessor的类,并展示postProcessBeforeInitialization和postProcessAfterInitialization方法。然后,InitializingBean的例子,实现afterPropertiesSet方法。@PostConstruct注解的使用方式。FactoryBean的例子,比如如何创建一个FactoryBean来生成特定类型的bean。同时,要提到配置方式,比如使用@Component或者@Configuration来注册这些类。 还要注意引用中的内容,比如引用[3]提到InitializingBean和@PostConstruct,所以需要正确引用这些部分。可能生成的引用标识应该是[^3]和[^1]。此外,示例代码需要符合用户提供的格式,可能用Java而不是Python,但用户给出的示例是Python,但问题本身是关于Spring Boot的,所以应该用Java代码块。 最后,生成相关问题,比如不同扩展点的执行顺序,如何选择扩展点,或者如何结合AOP使用扩展点。确保问题相关且基于内容。</think>### Spring Boot自定义扩展点实现方式 在Spring Boot中实现自定义扩展点主要依赖于Spring框架的生命周期接口和注解机制。以下是三种核心实现方式及示例: --- #### 一、实现**BeanPostProcessor**接口 用于在Bean初始化前后插入自定义逻辑,例如修改属性或代理对象。 ```java @Component public class CustomBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) { System.out.println("Before初始化: " + beanName); return bean; // 可返回修改后的对象 } @Override public Object postProcessAfterInitialization(Object bean, String beanName) { System.out.println("After初始化: " + beanName); return bean; } } ``` *执行顺序*:此接口方法会在每个Bean的初始化阶段被调用[^1]。 --- #### 二、使用**InitializingBean**接口或**@PostConstruct** 1. **实现InitializingBean接口** ```java @Component public class CustomInitBean implements InitializingBean { @Override public void afterPropertiesSet() { System.out.println("Bean属性注入完成后执行"); } } ``` 2. **使用@PostConstruct注解** ```java @Component public class AnnotationInitBean { @PostConstruct public void init() { System.out.println("@PostConstruct方法执行"); } } ``` *特点*:两者均在Bean属性注入完成后触发,但注解方式更灵活。 --- #### 三、通过**FactoryBean**定制复杂对象 用于创建无法直接通过构造函数实例化的对象(如第三方库组件)。 ```java @Component public class MyFactoryBean implements FactoryBean<SpecialService> { @Override public SpecialService getObject() { return new SpecialService("自定义配置参数"); } @Override public Class<?> getObjectType() { return SpecialService.class; } } ``` *调用方式*:通过`applicationContext.getBean("myFactoryBean")`获取实例。 --- #### 四、扩展点执行顺序参考 $$ \begin{aligned} &1.\ BeanPostProcessor.postProcessBeforeInitialization \\ &2.\ @PostConstruct/\ InitializingBean.afterPropertiesSet \\ &3.\ BeanPostProcessor.postProcessAfterInitialization \end{aligned} $$ 该顺序体现了Spring容器对Bean生命周期的精细控制[^1]。 ---
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

凡夫贩夫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值