Серия SpringBoot — жизненный цикл и расширение компонентов Bean

Spring Boot задняя часть Spring

Эта статья основана на версии SpringBoot 2.2.2.RELEASE, между различными версиями Spring есть некоторые отличия, но основной процесс в основном одинаков, на это нужно обращать внимание в процессе чтения.

Рекомендуемое чтение

Содержание этой статьи

Перед чтениемВремя и процесс анализа TestBeanService в BeanDifinitionАнализ процесса выполнения invokeBeanFactoryPostProcessorsАнализ процесса выполнения invokeBeanDefinitionRegistryPostProcessorsМодификация BeanDefinition с помощью BeanFactoryPostProcessorИзмените значение свойства, прослушивая событие ApplicationEnvironmentPreparedEvent.@Value Injection и @Autowired InjectionКогда происходит внедрение свойства компонентаКак происходит внедрение свойств компонентаПроцесс создания экземпляра компонентаВремя обработки BeanPostProcessorМодифицируйте бины с помощью BeanPostProcessorИспользование InitializingBeanОпределяет метод init-метода bean-компонентаСуммироватьВлияние BeanFactoryPostProcessor на метод инициализацииПриложение: адрес проекта кейса и ссылка

Перед чтением

Продолжайте выполнять предыдущую статьюSpringBoot Series — Анализ процесса запуска, эта статья посвящена жизненному циклу компонента, внося в него некоторые модификации и расширения. Ниже приведен «главный герой» TestBeanService этой статьи, определенный следующим образом:

public class TestBeanService {
    /**
     * 依赖注入
     */
    @Autowired
    private InjectBeanService injectBeanService;
    /**
     * 属性注入
     */
    @Value("${spring.application.name}")
    private String appName;

    public String test() {
        return injectBeanService.testInject();
    }
}

TestBeanService включает в себя два свойства, одно — injectBeanService, а другое — appName, которые вводят значения через @Autowired и @Value соответственно. Конечная цель этой статьи — завершить процесс понимания внедрения свойства Bean и процесс создания экземпляра Bean; кроме того, с точки зрения расширения Spring, понять время выполнения и время выполнения BeanFactoryPostProcess, BeanPostProcess, ApplicationListener. , анализируется эффект InitializingBean и initMethod.

Время и процесс анализа TestBeanService в BeanDifinition

Процесс обновления контейнера Spring очень сложен. Когда мы хотим отладить процесс загрузки BeanDifinition, мы не сможем быстро найти запись. Здесь мы можем напрямую отладить конечный пункт назначения BeanDifinition. Мы знаем, что сам интерфейс BeanFactory специально не регистрирует возможность BeanDifinition, которая предоставляется интерфейсом BeanDefinitionRegistry. Затем посмотрите на метод registerBeanDefinition BeanDefinitionRegistry, который имеет несколько конкретных реализаций, а затем установите точки останова в этих реализациях, чтобы найти конкретную запись обработки.

Мы попали в точку останова на входе метода DefaultListableBeanFactory#registerBeanDefinition, запустили проект в режиме отладки, и вы можете увидеть ситуацию при входе в точку останова, как показано на следующем рисунке:

Здесь запись загрузки BeanDifinition находится путем выполнения обратного стека, который представляет собой метод invokeBeanFactoryPostProcessors на этапе обновления контейнера; здесь представлен подробный анализ того, как beandifinition testBeanService регистрируется в контейнере.

Анализ процесса выполнения invokeBeanFactoryPostProcessors

Реализация метода invokeBeanFactoryPostProcessors очень длинная, но основной процесс обработки очень прост и включает множество повторяющихся шагов. Для того, чтобы облегчить понимание всего процесса, все же необходимо вставить сюда код.В коде будет подробно указано, что делается.Этот процесс является очень важным шагом в построении BeanFactory. Освойте этот процесс, и вы сможете поэкспериментировать с BeanFactoryPostProcessor по своему желанию.

public static void invokeBeanFactoryPostProcessors(
            ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {

    // Invoke BeanDefinitionRegistryPostProcessors first, if any.
    Set<String> processedBeans = new HashSet<>();
    // 当前 beanFactory 是否是 BeanDefinitionRegistry 类型
    // 只有是 BeanDefinitionRegistry 类型,才具备注册 beanDefinition 的能力
    if (beanFactory instanceof BeanDefinitionRegistry) {
        BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
        // 普通的 BeanFactoryPostProcessor 集合
        List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
        // BeanDefinitionRegistryPostProcessor 类型处理器集合
        List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
        // 这里 beanFactoryPostProcessors 是在 SharedMetadataReaderFactoryContextInitializer 中加进来的,是 Spring 自己的处理器
        for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
            // 如果是 BeanDefinitionRegistryPostProcessor 类型,就加到 registryProcessors
            if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
                BeanDefinitionRegistryPostProcessor registryProcessor =
                        (BeanDefinitionRegistryPostProcessor) postProcessor;
                // 执行 BeanDefinitionRegistryPostProcessor 后置处理
                registryProcessor.postProcessBeanDefinitionRegistry(registry);
                registryProcessors.add(registryProcessor);
            }
            else {
                // 否则就放到 regularPostProcessors
                regularPostProcessors.add(postProcessor);
            }
        }

        // 不要在这里初始化 FactoryBeans:需要保留所有未初始化的常规bean,以使 beanFacotryPostProcessor 对其处理!
        // 分离实现 PriorityOrdered,Ordered和其余优先级的 BeanDefinitionRegistryPostProcessor。
        List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

        // 首先,调用实现 PriorityOrdered 的 BeanDefinitionRegistryPostProcessors。
        String[] postProcessorNames =
                beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
        // 遍历 BeanDefinitionRegistryPostProcessors
        for (String ppName : postProcessorNames) {
            // 只处理实现 PriorityOrdered 接口的 BeanDefinitionRegistryPostProcessor
            if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
                // 符合上述条件的 BeanDefinitionRegistryPostProcessor 放到 currentRegistryProcessors 中,供后面使用
                currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                // 标记当前 postProcessor 已经处理过了
                processedBeans.add(ppName);
            }
        }
        // 排序
        sortPostProcessors(currentRegistryProcessors, beanFactory);
        registryProcessors.addAll(currentRegistryProcessors);
        // 调用 BeanDefinitionRegistryPostProcessor 后置处理器
        invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
        currentRegistryProcessors.clear();

        // 接下来,调用实现 Ordered的BeanDefinitionRegistryPostProcessors
        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();
        }

        // 现在,调用到目前为止已处理的所有处理器的 postProcessBeanFactory 回调。
        invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
        invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
    }

    else {
        // 调用在上下文实例中注册的工厂处理器。就是前面提到的 SharedMetadataReaderFactoryContextInitializer 中注册的
        invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
    }

    // 这里再次拿到所有的 BeanFactoryPostProcessor
    String[] postProcessorNames =
            beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);

    // 同样将实现 PriorityOrdered、Order 和普通的 BeanFactoryPostProcessor 分离开
    List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
    List<String> orderedPostProcessorNames = new ArrayList<>();
    List<String> nonOrderedPostProcessorNames = new ArrayList<>();
    for (String ppName : postProcessorNames) {
        if (processedBeans.contains(ppName)) {
            // 跳过-已在上述第一阶段处理过
        }
        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的BeanFactoryPostProcessors。
    sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
    // 优先执行实现 PriorityOrdered 接口的 BeanFactoryPostProcessor
    invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

    // 接下来,调用实现Ordered的BeanFactoryPostProcessors。
    List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
    for (String postProcessorName : orderedPostProcessorNames) {
        orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
    }
    sortPostProcessors(orderedPostProcessors, beanFactory);
    // 执行实现 Ordered 接口的 BeanFactoryPostProcessor
    invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);

    // 最后,调用所有其他 BeanFactoryPostProcessor
    List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
    for (String postProcessorName : nonOrderedPostProcessorNames) {
        nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
    }
    // 执行其他没有实现任何优先级接口的 BeanFactoryPostProcessor
    invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
    // 清除缓存的合并 beanDefinition,因为后处理器可能已经修改了原始元数据
    beanFactory.clearMetadataCache();
}

В приведенном выше сегменте кода сначала обрабатывается BeanFactoryPostProcessor типа BeanDefinitionRegistryPostProcessor, а затем обычный BeanFactoryPostProcessor; во время обработки порядок выполнения каждого BeanFactoryPostProcessor будет корректироваться в соответствии с некоторыми правилами сортировки.

Сначала необходимо обработать BeanFactoryPostProcessor типа BeanDefinitionRegistryPostProcessor, поскольку на этом этапе необходимо зарегистрировать BeanDefinition. После того, как все BeanDefinitions в пути к классам зарегистрированы, выполняется обратный вызов обычного BeanFactoryPostProcessor, чтобы можно было охватить все BeanDefinitions.

Анализ процесса выполнения invokeBeanDefinitionRegistryPostProcessors

При вызове invokeBeanDefinitionRegistryPostProcessors в первый раз существует только один текущий BeanDefinitionRegistryPostProcessor, которым является org.springframework.context.annotation.ConfigurationClassPostProcessor .

В классе ConfigurationClassPostProcessor анализируются такие аннотации, как @Configuration, @ComponentScan, @ComponentScans, @Import. ConfigurationClassPostProcessor реализует интерфейс BeanDefinitionRegistryPostProcessor, а интерфейс BeanDefinitionRegistryPostProcessor наследует интерфейс BeanFactoryPostProcessor, поэтому методы postProcessBeanDefinitionRegistry() и postProcessBeanFactory() необходимо переписать в ConfigurationClassPostProcessor. Эти два метода выполняют роль класса ConfigurationClassPostProcessor. Более подробную информацию можно найтиАнализ исходного кода ConfigurationClassPostProcessorЭта статья очень красиво написана.

Основной процесс обработки invokeBeanDefinitionRegistryPostProcessors выглядит следующим образом:

  • 1. ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry: BeanDefinition запускает запись загрузки
  • 2. ConfigurationClassPostProcessor#processConfigBeanDefinitions: проанализируйте класс конфигурации, где будут проанализированы аннотации к классу конфигурации (класс, сканируемый ComponentScan, класс, зарегистрированный @Import, и класс, определенный методом @Bean).
  • 3. ComponentScanAnnotationParser#parse: отфильтруйте и загрузите beanDefinition по пути к классам в соответствии со значением атрибута аннотации (условие по умолчанию — basePackages, basePackages по умолчанию — это корневой пакет текущего класса запуска)
  • 4. ClassPathBeanDefinitionScanner#doScan: обработайте все beanDefinition в basePackages, и классы, аннотированные с помощью @Service, @Compoment и т. д., будут проанализированы на
  • 5. DefaultListableBeanFactory#registerBeanDefinition: Зарегистрируйте beanDefinition в BeanFactory (в beanDefinitionMap)

Итак, здесь BeanDefinition TestBeanService зарегистрирован в BeanFactory.

Модификация BeanDefinition с помощью BeanFactoryPostProcessor

В случае проекта, соответствующего этой статье, также реализован BeanFactoryPostProcessor, а интерфейс сортировки не реализован. Роль этого TestBeanServiceBeanFactoryPostProcessor состоит в том, чтобы изменить исходный TestBeanService на ProxyTestBeanService. код показывает, как показано ниже:

public class TestBeanServiceBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // 根据类型拿到所有的 beanNames
        Iterable<String> beanNames = getBeanNames(beanFactory, TestBeanService.class);
        // 这里因为只有一个 TestBeanService ,所以只处理第一个
        beanNames.forEach(beanName -> {
            System.out.println("begin to execute BeanFactoryPostProcessor...");
            BeanDefinitionRegistry beanDefinitionRegistry = (BeanDefinitionRegistry) beanFactory;
            // 先从工程中拿到原始 beanDefinition
            BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
            // 这里构建一个新的 BeanDefinition,类型为 ProxyTestBeanService,ProxyTestBeanService 是 TestBeanService 的子类
            RootBeanDefinition proxy = new RootBeanDefinition(ProxyTestBeanService.class);
            // 这里设置指定的initMethod
            proxy.setInitMethodName(beanDefinition.getInitMethodName());
            // 设置一些属性
            proxy.setPropertyValues(beanDefinition.getPropertyValues());
            proxy.setPrimary(beanDefinition.isPrimary());
            proxy.setRole(BeanDefinition.ROLE_APPLICATION);
            // 将原始 beanDefinition 移除掉
            beanDefinitionRegistry.removeBeanDefinition(beanName);
            // 将代理的新的 beanDefinition 注册进去
            beanDefinitionRegistry.registerBeanDefinition(beanName,proxy);
            System.out.println("current bean type is : " + proxy.getBeanClass().getTypeName());
            return;
        });
    }
}

Время и процесс выполнения BeanFactoryPostProcessor были проанализированы при анализе процесса выполнения invokeBeanFactoryPostProcessors и не будут повторяться здесь. Функция TestBeanServiceBeanFactoryPostProcessor состоит в том, чтобы сначала удалить Beandefinition исходного TestBeanService из контейнера, затем построить Beandefinition ProxyTestBeanService, а затем зарегистрировать его в контейнере.BeanName не изменилось, поэтому самая примитивная информация Bean может быть изменена через BeanFactoryPostProcessor. , или BeanFactoryPostProcessor можно использовать для изменения исходной информации Bean Для динамической регистрации нового Bean.

Измените значение свойства, прослушивая событие ApplicationEnvironmentPreparedEvent.

Вышеизложенное завершает модификацию BeanDefinition TestBeanService, заменяя объект TestBeanService на ProxyTestBeanService. Как упоминалось ранее, есть два значения, которые необходимо внедрить в TestBeanService, одно вводится через @Autowired, а другое вводится через @Value, Давайте сначала рассмотрим внедрение @Value. Значение, вводимое @Value, поступает из среды.О среде и анализе и построении конфигурации говорить особо нечего.Эта статья посвящена тому, как изменить значение, вводимое @Value.

Событие ApplicationEnvironmentPreparedEvent — это событие, отправляемое, когда подготовка среды завершена и среда готова предоставить поддержку переменных среды для обновления контейнера в любое время. Затем, поскольку объект Environment в контейнере в это время готов, это означает, что настроенные application.properties, системные параметры и т. д. были проанализированы, и целевой компонент не был обновлен в это время, а значения внутренних свойств которые должны быть введены, не были проанализированы. Внедрите, затем вы можете изменить значение, которое было подготовлено в среде, прослушивая это событие в это время, чтобы изменить значение, которое фактически вводится. код показывает, как показано ниже:

public class ChangeAppNameListener implements ApplicationListener<ApplicationEnvironmentPreparedEvent> {
    @Override
    public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
        ConfigurableEnvironment environment = event.getEnvironment();
        // 获取原始 spring.application.name 的值
        String applicationName = environment.getProperty("spring.application.name");
        System.out.println("origin applicationName is : " + applicationName);
        // 修改 spring.application.name
        Properties props = new Properties();
        props.put("spring.application.name", "updateAppName");
        environment.getPropertySources().addFirst(new PropertiesPropertySource("decrypted_properties", props));

        applicationName = environment.getProperty("spring.application.name");
        System.out.println("updated applicationName is : " + applicationName);
    }
}

@Value Injection и @Autowired Injection

В Spring как внедрение @Value, так и внедрение @Autowired обрабатываются постпроцессором AutowiredAnnotationBeanPostProcessor.

Во многих платформах с открытым исходным кодом большая часть их внутренних пользовательских аннотаций обрабатывается через постпроцессор BeanPostProcessor.

В AutowiredAnnotationBeanPostProcessor есть внутренний класс AutowiredFieldElement, функция которого заключается во внедрении значения свойства целевого компонента. Это включает внедрение @Value и внедрение @Autowired.

Когда происходит внедрение свойства компонента

Стек вызовов обновления контейнера и внедрения свойств выглядит следующим образом:

Как видно из стека, на заключительном этапе обновления контейнера все оставшиеся (не отложенная инициализация) одноэлементные компоненты создаются с помощью метода finishBeanFactoryInitialization; этот процесс является процессом создания большинства компонентов. Этот процесс будет включать в себя еще два важных момента: 1. Обработка BeanPostProcessor, 2. Внедрение зависимостей. Как видно из вышеизложенного, возникновение внедрения зависимостей завершается обработкой BeanPostProcessor. На следующем рисунке показан процесс последовательного обхода всех целевых свойств и внедрения свойств:

Как происходит внедрение свойств компонента

Взяв в качестве примера внедрение @Autowired, процесс внедрения @Value и внедрения @Autowired в основном одинаков. По сравнению с внедрением @Value внедрение @Autowired включает в себя процесс инициализации другого компонента.

// 构建一个依赖描述符对象
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
// 设置包含此依赖项的具体类
desc.setContainingClass(bean.getClass());
// 初始化一个注入的 beanName 集合,用于后面注册到容器中
// 这里实际上只有一个,如果有多个实例 bean 存在,则需要通过 Qualifier 指定了
Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
Assert.state(beanFactory != null, "No BeanFactory available");
TypeConverter typeConverter = beanFactory.getTypeConverter();
try {
    // 解析依赖,依赖注入
    value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
}
catch (BeansException ex) {
    // 抛出注入失败异常
    throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
}
synchronized (this) {
    if (!this.cached) {
        if (value != null || this.required) {
            this.cachedFieldValue = desc;
            // 注册依赖的 bean
            registerDependentBeans(beanName, autowiredBeanNames);
            if (autowiredBeanNames.size() == 1) {
                String autowiredBeanName = autowiredBeanNames.iterator().next();
                // 判断容器中是否存在此依赖 bean,并且校验 bean 的类型是否匹配
                if (beanFactory.containsBean(autowiredBeanName) &&
                        beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
                    // 缓存注入值
                    this.cachedFieldValue = new ShortcutDependencyDescriptor(
                            desc, autowiredBeanName, field.getType());
                }
            }
        }
        else {
            // 没有找到 依赖bean 实例,且 required 为 false 
            this.cachedFieldValue = null;
        }
        this.cached = true;
    }
}
// value 为解析到的属性值,如果不为空,则通过反射设置给目标 Bean,完成属性的注入
if (value != null) {
    ReflectionUtils.makeAccessible(field);
    field.set(bean, value);
}

Внедрение атрибута происходит в процессе populateBean (заполнение Bean-компонента), а процесс создания экземпляра Bean-компонента завершается после заполнения атрибута Bean-компонента.

Процесс создания экземпляра компонента

Вот фрагмент кода из метода AbstractAutowireCapableBeanFactory#doCreateBean для получения контекста:

// 初始化bean实例。
Object exposedObject = bean;
try {
    // 填充 Bean
    populateBean(beanName, mbd, instanceWrapper);
    // 实例化 Bean
    exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
    // 省略异常处理
}

Код здесь хорошо связан с содержанием предыдущего раздела, то есть populate Bean -> Instantiate Bean. На этапе создания экземпляра Bean участвуют два важных расширения: 1. BeanPostProcessor, 2. InitializingBean.

Время обработки BeanPostProcessor

BeanPostProcessor имеет два абстрактных метода, один из которых вызывается перед созданием экземпляра, а другой — после создания. Интерфейс InitializingBean имеет только один метод afterPropertiesSet, и выполнение метода afterPropertiesSet происходит между вызовами до создания экземпляра и после создания экземпляра. Время обработки BeanPostProcessor запускается при вызове метода initializeBean Ниже приведены некоторые фрагменты кода в методе initializeBean:

Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
    // 实例化之前调用
    wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
    // 调用 InitializingBean 和指定的 init-method 方法
    invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
    throw new BeanCreationException(
            (mbd != null ? mbd.getResourceDescription() : null),
            beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
    // 实例化之后调用
    wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}

Объект bean-компонента здесь на самом деле является законченным bean-компонентом, postProcessBeforeInitialization и postProcessAfterInitialization относятся к тому, следует ли выполнять afterPropertiesSet InitializingBean и выполнять ли метод initMethod, указанный bean-компонентом.

Модифицируйте бины с помощью BeanPostProcessor

Как видно из метода initializeBean, два обратных вызова postProcessBeforeInitialization и postProcessAfterInitialization возвращают завернутыйBean, а это означает, что мы можем выполнять некоторую обработку исходного Bean в контейнере в этих двух методах, например, проксировать слой исходного Bean или модифицировать некоторые свойства в Bean и т.д.

В проекте case предоставляется TestBeanServiceProcessor, и его функция заключается в создании уровня прокси для Bean типа TestBeanService, так что некоторые скрытые точки создаются до и после выполнения метода в TestBeanService.

// TestBeanServiceProcessor
public class TestBeanServiceProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        // 如果 bean 的类型是 TestBeanService,则将其包装成 TestBeanWrapperService 并返回
        if (bean instanceof TestBeanService){
            System.out.println("begin to execute postProcessBeforeInitialization.");
            TestBeanWrapperService testBeanService = new TestBeanWrapperService((TestBeanService)bean);
            return testBeanService;
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof TestBeanService){
            System.out.println("begin to execute postProcessAfterInitialization.");
        }
        return bean;
    }
}
// 代理类 TestBeanWrapperService,注意这里代理类也应该是 TestBeanService 类型,否在是后面使用时就会找不到 Bean 实例
public class TestBeanWrapperService extends TestBeanService {
    private final TestBeanService delegate;
    public TestBeanWrapperService(TestBeanService delegate){
        this.delegate = delegate;
    }

    /**
     * 实现对 test 方法执行前后进行拦截
     **/
    @Override
    public String test() {
        try {
            before();
            return delegate.test();
        } finally {
            after();
        }
    }

    private void before(){
        System.out.println("before execute test.");
    }

    private void after(){
        System.out.println("after execute test.");
    }
}

Использование InitializingBean

Если компонент интегрирует интерфейс InitializingBean, то его метод afterPropertiesSet необходимо переопределить. Это кажется немного зацикленным.Действие afterPropertiesSet уже завершено.Кроме того, поскольку afterPropertiesSet вызывается перед методом postProcessAfterInitialization, свойства все еще могут быть изменены в postProcessAfterInitialization. В процессе реального использования нам нужно обратить внимание на этот момент.В общем, мы будем делать некоторые действия по инициализации в afterPropertiesSet, такие как запуск подключения к Zookeeper.

public class TestBeanService implements InitializingBean {
    // 省略其他代码
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("begin to execute afterPropertiesSet...");
    }
}

Определяет метод init-метода bean-компонента

Метод init-method может быть указан только с помощью @Bean или xml.Если стандартный Bean аннотирован с помощью @Component или @Service, метод может быть аннотирован с помощью @PostConstruct, что соответствует методу destroy и @PreDestroy.

public class TestBeanService implements InitializingBean{
    // 省略其他代码

    // init 方法
    public void init(){
        System.out.println("begin to execute init...");
    }
}
// 在自动配置类或者 xml 文件中指定 initMethod
@Bean(initMethod = "init")
public TestBeanService testBeanService(){
    return new TestBeanService();
}

Суммировать

Эта статья посвящена компоненту TestBeanService и представляет его жизненный цикл и его точки расширения на различных этапах жизненного цикла, включая изменение введенных значений атрибутов, изменение его BeanDefinition, изменение экземпляров компонента и т. д., с точки зрения точек расширения для получения понимание жизненного цикла Bean.

Влияние BeanFactoryPostProcessor на метод инициализации

Т.к. пункт init-method был добавлен позже, в процессе реального тестирования было обнаружено, что init-метод, указанный в TestBeanService, не был выполнен (обычно он будет выполняться после afterPropertiesSet); для этого TestBeanService в кейс-проекте есть две модификации к нему, одна для изменения его BeanDefinition, другая для изменения его экземпляра Bean; последний тип компонента — TestBeanWrapperService, а до этого тип компонента — ProxyTestBeanService, и TestBeanWrapperService, и ProxyTestBeanService являются TestBeanService Метод init является общедоступным, поэтому с этой точки зрения нельзя не действовать. Поэтому в принципе можно исключить, что это вызвано проблемами с правами доступа. Наконец, отладьте следующий код и обнаружите, что mbd.getInitMethodName() возвращает значение null, а mbd — это RootBeanDefinition;

PS: метод getInitMethodName в BeanDefinition доступен только после Spring 5.1.Предыдущие версии были определены в абстрактном классе AbstractBeanDefinition.

if (mbd != null && bean.getClass() != NullBean.class) {
    // 从当前 bean  的 BeanDefinition 对象中获取 initMethod 方法名
    String initMethodName = mbd.getInitMethodName();
    if (StringUtils.hasLength(initMethodName) &&
            !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
            !mbd.isExternallyManagedInitMethod(initMethodName)) {
        invokeCustomInitMethod(beanName, bean, mbd);
    }
}

Проблема заключается в том, что когда TestBeanServiceBeanFactoryPostProcessor обрабатывается, initMethod исходного BeanDefinition не передается новому ProxyTestBeanService, поэтому все последующие BeanDefinitions, основанные на этом экземпляре bean-компонента, не имеют метода initMethod. После добавления InitMethodName в метод TestBeanServiceBeanFactoryPostProcessor#postProcessBeanFactory проблема решена.

// 这里设置指定的initMethod
proxy.setInitMethodName(beanDefinition.getInitMethodName());

Приложение: адрес проекта кейса и ссылка