参考文献

SpringBoot扩展点

  • ApplicationContextInitializer
  • BeanDefinitionRegistryPostProcessor
  • BeanFactoryPostProcessor
  • InstantiationAwareBeanPostProcessor
  • SmartInstantiationAwareBeanPostProcessor
  • BeanFactoryAware
  • ApplicationContextAwareProcessor
  • BeanNameAware
  • InitializingBean
  • FactoryBean
  • SmartInitializingSingleton
  • CommandLineRunner
  • DisposableBean
  • ApplicationListener

ApplicationContextInitializer

1
2
3
4
5
6
package org.springframework.context;

@FunctionalInterface
public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> {
void initialize(C applicationContext);
}

触发时机

  • ApplicationContextInitializer接口的实现类的执行时机是在Spring容器正式刷新前,准备上下文环境时.
1
2
3
4
5
6
7
org.springframework.boot.SpringApplication#run(java.lang.String...)
-->
org.springframework.boot.SpringApplication#prepareContext
-->
org.springframework.boot.SpringApplication#applyInitializers
-->
org.springframework.context.ApplicationContextInitializer#initialize
1
2
3
4
5
6
7
8
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);
}
}

使用步骤

  1. 实现ApplicationContextInitializer接口

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    package cn.holelin.spring.extend;

    import org.springframework.context.ApplicationContextInitializer;
    import org.springframework.context.ConfigurableApplicationContext;

    import java.util.Map;

    public class TestApplicationContextInitializer implements ApplicationContextInitializer {
    @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容器中

    1. 方法一: 调用org.springframework.boot.SpringApplication#addInitializers方法将实现的类添加到容器中

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13

      import cn.holelin.spring.extend.TestApplicationContextInitializer;
      import org.springframework.boot.SpringApplication;
      import org.springframework.boot.autoconfigure.SpringBootApplication;

      @SpringBootApplication
      public class Application {
      public static void main(String[] args) {
      SpringApplication springApplication = new SpringApplication(Application.class);
      springApplication.addInitializers(new TestApplicationContextInitializer());
      springApplication.run(args);
      }
      }
    2. 方法二: 通过在项目的resources目录下创建META-INF/spring.factories,将实现类配置到该文件中

      1
      org.springframework.context.ApplicationContextInitializer=cn.holelin.spring.extend.TestApplicationContextInitializer
      • 原理:

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        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();
        this.bootstrapRegistryInitializers = new ArrayList<>(
        getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
        // 关键点,构造函数中会去META-INF/spring.factories下配置的所有initializers添加到容器中
        setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
        setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
        this.mainApplicationClass = deduceMainApplicationClass();
        }
    3. 方法三: 通过在application.yaml配置文件中配置

      1
      2
      3
      context:
      initializer:
      classes: cn.holelin.spring.extend.TestApplicationContextInitializer
      • 原理: 方法二中META-INF/spring.factoriesorg.springframework.boot.context.config.DelegatingApplicationContextInitializer类用于处理context.initializer.classes配置

BeanDefinitionRegistryPostProcessor

  • 作用: BeanDefinitionRegistryPostProcessorBeanFactoryPostProcessor的一个子接口,它提供了更早期的回调时机,使你可以在bean定义注册时干预Spring IoC容器的初始化流程,甚至可以动态注册、修改或移除BeanDefinition.

  • 使用场景: 当你需要在容器初始化阶段注册新的bean定义,或者修改和删除已经注册的bean定义时,应该使用BeanDefinitionRegistryPostProcessor.例如,动态注册一些依赖于外部条件的bean或者从注册中心中删除某些bean.

BeanFactoryPostProcessor vs BeanDefinitionRegistryPostProcessor

  • BeanFactoryPostProcessor: 主要用于在所有的BeanDefinition都被加载到BeanFactory后,修改已存在的BeanDefinition.不能在BeanFactoryPostProcessor中动态注册新的BeanDefinition
  • BeanDefinitionRegistryPostProcessor: 不仅能够修改BeanDefinition,还允许动态注册和删除BeanDefinition.它的回调时机比BeanFactoryPostProcessor早,允许对BeanDefinitionRegistry进行直接操作.

触发时机

1
2
3
4
5
6
7
8
9
org.springframework.context.support.AbstractApplicationContext#refresh
-->
org.springframework.context.support.AbstractApplicationContext#invokeBeanFactoryPostProcessors
-->
org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors
-->
org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanDefinitionRegistryPostProcessors
-->
org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry
  • PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors()方法中,并不是直接就初始化和执行postProcessBeanDefinitionRegistry()postProcessBeanFactory(),而是又进行了一系列的判断,其判断顺序是:
    1. 通过AbstractApplicationContext#addBeanFactoryPostProcessor提前注册的BeanDefinitionRegistryPostProcessor实现类;
    2. 实现了PriorityOrdered接口;
    3. 是否实现了Ordered;
    4. 剩下的其他BeanDefinitionRegistryPostProcessor实现类
1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* Invoke the given BeanDefinitionRegistryPostProcessor beans.
*/
private static void invokeBeanDefinitionRegistryPostProcessors(
Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry, ApplicationStartup applicationStartup) {

for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
StartupStep postProcessBeanDefRegistry = applicationStartup.start("spring.context.beandef-registry.post-process")
.tag("postProcessor", postProcessor::toString);
postProcessor.postProcessBeanDefinitionRegistry(registry);
postProcessBeanDefRegistry.end();
}
}

使用步骤

  • 实现BeanDefinitionRegistryPostProcessor接口,在postProcessBeanDefinitionRegistry中实现具体逻辑

BeanFactoryPostProcessor

触发时机

  • 调用时机在Spring在读取beanDefinition信息之后,实例化bean之前
1
2
3
4
5
6
7
8
org.springframework.context.support.AbstractApplicationContext#refresh
-->
org.springframework.context.support.AbstractApplicationContext#invokeBeanFactoryPostProcessors
-->
org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors
-->
// 在org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanDefinitionRegistryPostProcessors之后
org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors

InstantiationAwareBeanPostProcessor

  • BeanPostProcess接口只在bean的初始化阶段进行扩展(注入Spring上下文前后),而InstantiationAwareBeanPostProcessor接口在此基础上增加了3个方法,把可扩展的范围增加了实例化阶段和属性注入阶段.
  • 该类主要的扩展点有以下5个方法,主要在bean生命周期的两大阶段: 实例化阶段初始化阶段
    • postProcessBeforeInstantiation: 实例化bean之前,相当于new这个bean之前
    • postProcessAfterInstantiation: 实例化bean之后,相当于new这个bean之后
    • postProcessPropertyValues: bean已经实例化完成,在属性注入时阶段触发,@Autowired,@Resource等注解原理基于此方法实现
    • postProcessBeforeInitialization: 初始化bean之前,相当于把bean注入Spring上下文之前
    • postProcessAfterInitialization: 初始化bean之后,相当于把bean注入Spring上下文之后