Punto de extensión Springboot BeanFactoryPostProcessor

Colección de métodos de implementación y principios de funcionamiento de la serie de puntos de extensión Springboot:

Punto de extensión Springboot ApplicationContextInitializer

Punto de extensión Springboot BeanFactoryPostProcessor

Punto de extensión Springboot BeanDefinitionRegistryPostProcessor

Punto de extensión Springboot BeanPostProcessor

Punto de extensión Springboot InstantiationAwareBeanPostProcessor

Punto de extensión Springboot SmartInstantiationAwareBeanPostProcessor

Punto de extensión Springboot ApplicationContextAwareProcessor

Punto de extensión Springboot @PostConstruct

Punto de extensión Springboot InicializandoBean

Punto de extensión Springboot SmartInitializingSingleton

Punto de extensión Springboot CommandLineRunner y ApplicationRunner

Punto de extensión Springboot FactoryBean

Punto de extensión Springboot DesechableBean

El final de la serie de puntos de extensión Springboot: ciclo de vida del Bean

Insertar descripción de la imagen aquí

1. Características funcionales

  1. La ejecución de BeanFactoryPostProcessor es una parte muy importante del ciclo de vida de Spring Bean;
  2. El postprocesador de nivel BeanFactory, org.springframework.beans.factory.config.BeanFactoryPostProcessor#postProcessBeanFactory solo se ejecutará una vez durante el ciclo de vida de Spring;
  3. Permite que los datos de BeanDefinition se lean después de que el contenedor lea los datos de BeanDefinition y antes de que se cree una instancia del bean, y se pueden modificar según sea necesario;

2. Método de implementación

Defina una clase de Perro, el atributo de nombre predeterminado es "Wangcai" y el color predeterminado es "negro";

@Data
@Component
public class Dog {
    
    
    private String name="旺财";
    private String color="黑色";
}

Defina una clase de implementación (MyBeanFactoryPostProcessor), implemente la interfaz org.springframework.beans.factory.config.BeanFactoryPostProcessor, anule el método postProcessBeanFactory() y cambie el nombre del atributo de la clase Dog a "huevo de perro"; y marque la interfaz BeanFactoryPostProcessor con la clase de implementación de anotación @Component (MyBeanFactoryPostProcessor);

@Component
@Slf4j
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    
    
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    
    
        log.info("com.fanfu.config.MyBeanFactoryPostProcessor.postProcessBeanFactory被执行");
        ScannedGenericBeanDefinition dog = ((ScannedGenericBeanDefinition) beanFactory.getBeanDefinition("dog"))  ;
        MutablePropertyValues propertyValues = dog.getPropertyValues();
        propertyValues.addPropertyValue("name", "狗蛋儿");
        log.info("修改Dog的BeanDefinition对象中的name属性为狗蛋儿");
    }
}

Escribir pruebas unitarias para verificar los resultados;

@SpringBootTest
@Slf4j
public class FanfuApplicationTests {
    
    
    @Test
    public void test(){
    
    
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext("com.fanfu");
        Dog dog = ((Dog) context.getBean("dog"));
        log.info(dog.getName());
        Assert.isTrue(dog.getName().equals("狗蛋儿"), "属性修改失败");
    }
}

Los resultados de la verificación muestran que la clase de implementación de la interfaz personalizada BeanFactoryPostProcessor (MyBeanFactoryPostProcessor) puede leer los datos BeanDefiniion después de que el contenedor lee los datos BeanDefinition del bean y antes de que se cree una instancia del bean, y modificarlos según sea necesario, luego el BeanFactoryPostProcessor personalizado ¿Qué es? ¿Cuál es el principio de funcionamiento de la clase de implementación de la interfaz (MyBeanFactoryPostProcessor)? ¿Cuándo se crea una instancia de la clase de implementación de la interfaz BeanFactoryPostProcessor? ¿Cómo se llama al método MyBeanFactoryPostProcessor#postProcessBeanFactory? Luego mira hacia abajo.

3. Principio de funcionamiento

3.1 ¿Cuándo se crea una instancia de la clase de implementación de la interfaz BeanFactoryPostProcessor?

  1. La clase de implementación de la interfaz BeanFactoryPostProcessor (MyBeanFactoryPostProcessor) está marcada con @Component y se encapsulará en un objeto BeanDefinition y se registrará en el contenedor cuando se inicie la ventana;
    Insertar descripción de la imagen aquí
  2. Cuando se ejecuta el método PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors(), los nombres de todas las clases de implementación del tipo BeanFactoryPostProcessor se encontrarán en el contenedor Spring según el tipo;
    Insertar descripción de la imagen aquí
  3. Después de obtener los nombres de todas las clases de implementación del tipo BeanFactoryPostProcessor en el paso anterior, realice un bucle nuevamente para crear una instancia de la clase de implementación de BeanFactoryPostProcessor (beanFacotry.getBean() para obtener la instancia de MyBeanFactoryPostProcessor. Si no se puede obtener, cree una);
    Insertar descripción de la imagen aquí

3.2 ¿Cómo se llama al método MyBeanFactoryPostProcessor#postProcessBeanFactory?

  1. En la prueba unitaria se construye un objeto AnnotationConfigApplicationContext. El método de construcción de AnnotationConfigApplicationContext es el siguiente:
public AnnotationConfigApplicationContext(String... basePackages) {
    
    
   this();
   scan(basePackages);
   refresh();
}
  1. En el método de construcción de AnnotationConfigApplicationContext anterior, puede ver que se vuelve a llamar a refresco(). Lo que en realidad se llama aquí es org.springframework.context.support.AbstractApplicationContext#refresh(). Este método también es un método clave para iniciar Spring contenedor A menudo se encuentra al analizar el código fuente relacionado con Spring.

  2. En AbstractApplicationContext#refresh(), llamar al método org.springframework.context.support.AbstractApplicationContext#invokeBeanFactoryPostProcessors inicia oficialmente la llamada al método postProcessBeanFactory() de todas las clases de implementación de la interfaz BeanFactoryPostProcessor;

  3. Siga el método AbstractApplicationContext#invokeBeanFactoryPostProcessors y encontrará que esto es solo una entrada. La tarea de ejecución de llamada real es el método org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors ();

  4. Después de seguir el método PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors(), descubrirá que realmente hay un mundo entero en su interior y es fácil perderse (lleve sus propias preguntas y analice el código fuente para encontrar las respuestas, no se deje confundir por cosas aparte de sus propias preguntas, definitivamente encontrará un futuro brillante) Además, la clase de implementación de org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor también se llama en este método, por lo que este método es muy valioso, así que lo haré Sácalo por separado y analízalo detenidamente. Se recomienda depurarlo y leerlo paso a paso y leerlo varias veces. Puedes entender que en realidad es muy simple. La única dificultad es que este método es un poco largo y requiere más paciencia y tiempo.

public static void invokeBeanFactoryPostProcessors(
      ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
    
    
   //之所以说这个方法的含金量很高,
   //是因为在这个方法里是先执行BeanDefinitionRegistryPostProcessor实现类的postProcessBeanDefinitionRegistry方法; 
   //然后才接着执行BeanFactoryPostProcessor接口的实现类的postProcessBeanFactory方法
   //这两个接口很表面上看很类似,实际在执行的时机和功能上是有明显区别的
   Set<String> processedBeans = new HashSet<>();
   //AnnotationConfigApplicationContext继承于GenericApplicationContext,
   //而GenericApplicationContext又实现了BeanDefinitionRegistry接口
   //所以这里会进入if语句中
   if (beanFactory instanceof BeanDefinitionRegistry) {
    
    
      BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
      List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
      List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
        //这里提前执行的BeanFactoryPostProcessor,是在准备上下文环境时,发布了ApplicationPreparedEvent事件;
        //触发监听器,通过AbstractApplicationContext#addBeanFactoryPostProcessor注册进来的;
        //这里并不是这次要重点分析的内容,可以先跳过这; 
      for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
    
    
         if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
    
    
            BeanDefinitionRegistryPostProcessor registryProcessor =
                  (BeanDefinitionRegistryPostProcessor) postProcessor;
            registryProcessor.postProcessBeanDefinitionRegistry(registry);
            registryProcessors.add(registryProcessor);
         }
         else {
    
    
            regularPostProcessors.add(postProcessor);
         }
      }
      List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
      // 从32行到72行,是在执行BeanDefinitionRegistryPostProcessor实现类的postProcessBeanDefinitionRegistry方法;
      //执行的过程也是有点小区折的,分三步,第一,执行实现了PriorityOrdered接口的实现类.
      String[] postProcessorNames =
            beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
      for (String ppName : postProcessorNames) {
    
    
         if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
    
    
            currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
            processedBeans.add(ppName);
         }
      }
      sortPostProcessors(currentRegistryProcessors, beanFactory);
      registryProcessors.addAll(currentRegistryProcessors);
      invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
      currentRegistryProcessors.clear();
      // 第二,执行实现了Ordered接口的实现类;
      postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
      for (String ppName : postProcessorNames) {
    
    
         if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
    
    
            currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
            processedBeans.add(ppName);
         }
      }
      sortPostProcessors(currentRegistryProcessors, beanFactory);
      registryProcessors.addAll(currentRegistryProcessors);
      invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
      currentRegistryProcessors.clear();
      //第三,执行剩下其他的BeanDefinitionRegistryPostProcessor实现类;
      boolean reiterate = true;
      while (reiterate) {
    
    
         reiterate = false;
         postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
         for (String ppName : postProcessorNames) {
    
    
            if (!processedBeans.contains(ppName)) {
    
    
               currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
               processedBeans.add(ppName);
               reiterate = true;
            }
         }
         sortPostProcessors(currentRegistryProcessors, beanFactory);
         registryProcessors.addAll(currentRegistryProcessors);
         invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
         currentRegistryProcessors.clear();
      }
      // BeanDefinitionRegistryPostProcessor继承了BeanFactoryPostProcessor,
      //所以这部分实现类的postProcessBeanFactory()会提前执行
      invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
      //第26行,非BeanDefinitionRegistryPostProcessor类型的BeanFactoryPostProcessor实现类会在这执行
      invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
   } else {
    
    
      invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
   }
   //BeanDefinitionRegistryPostProcessor接口的实现类上面已执行执行完了
   //下面开始准备执行BeanFactoryPostProcessor接口的实现类
   String[] postProcessorNames =
         beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
   // 正式执行前,把BeanFactoryPostProcessor接口的实现类分成了三类,
   //分别是实现了PriorityOrdered接口,实现了Ordered接口,其他;
   List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
   List<String> orderedPostProcessorNames = new ArrayList<>();
   List<String> nonOrderedPostProcessorNames = new ArrayList<>();
   for (String ppName : postProcessorNames) {
    
    
      if (processedBeans.contains(ppName)) {
    
    
         // skip - already processed in first phase above
      }
      else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
    
    
         priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
      }
      else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
    
    
         orderedPostProcessorNames.add(ppName);
      }
      else {
    
    
         nonOrderedPostProcessorNames.add(ppName);
      }
   }
   // 分好类,第一,先执行实现了PriorityOrdered接口的实现类; 
   sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
   invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
   // 第二,执行实现了Ordered接口的实现类; 
   List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
   for (String postProcessorName : orderedPostProcessorNames) {
    
    
      orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
   }
   sortPostProcessors(orderedPostProcessors, beanFactory);
   invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
   //第三,执行未实现上面两个接口的实现类,自定义的MyBeanFactoryPostProcessor就是在这里被执行的
   //其实,也很简单的,和BeanDefinitionRegistryPostProcessor接口的实现类的执行过程类似; 
   List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
   for (String postProcessorName : nonOrderedPostProcessorNames) {
    
    
      nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
   }
   invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
   beanFactory.clearMetadataCache();
}

3.3 Diagrama de secuencia de llamadas

Aquí he dibujado un diagrama de tiempo para que puedas ver todo el proceso de llamada de manera más intuitiva, también puedes seguir este diagrama y depurarlo paso a paso para comprender todo el proceso;
Insertar descripción de la imagen aquí

3.4postProcessBeanFactory()postProcessBeanDefinitionRegistry()

Al analizar el método PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors(), la diferencia entre postProcessBeanFactory() y postProcessBeanDefinitionRegistry() ya es obvia. Aquí hay un resumen (si hay alguna inexactitud en el resumen, dímelo en el área de comentarios para que podamos avanzar). juntos):

  1. El método postProcessBeanDefinitionRegistry de la clase de implementación de la interfaz BeanDefinitionRegistryPostProcessor se ejecutará antes que el método postProcessBeanFactory de la clase de implementación de la interfaz BeanFactoryPostProcessor;

  2. El parámetro formal del método postProcessBeanDefinitionRegistry es BeanDefinitionRegistry, y el parámetro formal del método postProcessBeanFactory es ConfigurableListableBeanFactory. Habrá algunas diferencias en las funciones. Cabe señalar que DefaultListableBeanFactory implementa las interfaces BeanDefinitionRegistry y ConfigurableListableBeanFactory;

  3. BeanDefinitionRegistryPostProcessor hereda BeanFactoryPostProcessor. Acerca de BeanDefinitionRegistryPostProcessor, puede ir aquí: Punto de extensión Springboot BeanDefinitionRegistryPostProcessor ;

4. Escenarios de aplicación

Descifrado de información confidencial, como el cifrado y descifrado de la información de conexión de la base de datos: en el desarrollo empresarial real, las contraseñas de mysq y redis en realidad no son seguras cuando se configuran en texto sin cifrar en el archivo de configuración, y es necesario configurar la información de la contraseña cifrada; pero cuando La información de la contraseña cifrada se inyecta en la fuente de datos. La conexión a la base de datos MySQL definitivamente resultará en una conexión anormal, porque MySQL no conoce su método de cifrado ni su método de cifrado. Esto creará un requisito: la información de la base de datos configurada en el archivo de configuración debe estar cifrada, pero la información de la contraseña debe descifrarse en el programa antes de inyectar la información de la contraseña en la fuente de datos.

BeanFactoryPostProcessor puede resolver este problema: antes de utilizar la fuente de datos para conectarse a la base de datos, lee la información cifrada, realiza el procesamiento de descifrado y luego reemplaza la información cifrada en el contenedor Spring con la información descifrada.
——————————————
Declaración de derechos de autor: este artículo es un artículo original del blogger de CSDN "Ordinary Trafficker" y sigue el acuerdo de derechos de autor CC 4.0 BY-SA. Adjunte el enlace de la fuente original y esta copia. al reimprimir la declaración.
Enlace original: https://blog.csdn.net/fox9916/article/details/128823328

Supongo que te gusta

Origin blog.csdn.net/tian830937/article/details/132946304
Recomendado
Clasificación