Статьи

Взаимодействие с вновь созданными экземплярами bean-компонентов с использованием Spring BeanPostProcessor

Эта статья взята из книги Начало работы с Spring Framework

 

BeanPostProcessor используется для взаимодействия с вновь созданными экземплярами bean-компонентов до и / или после вызова их метода инициализации контейнером Spring. Вы можете использовать BeanPostProcessor для выполнения пользовательской логики до и / или после вызова метода инициализации bean-компонента контейнером Spring.

Интерфейс BeanPostProcessor определяет следующие методы:

  • Объект postProcessBeforeInitialization (Object bean, String beanName) — этот метод вызывается до вызова метода инициализации экземпляра компонента
  • Object postProcessAfterInitialization (Object bean, String beanName) — этот метод вызывается после вызова метода инициализации экземпляра компонента

Методы BeanPostProcessor принимают вновь созданный экземпляр компонента и его имя в качестве аргументов и возвращают тот же или измененный экземпляр компонента. Вы конфигурируете реализацию BeanPostProcessor в XML-файле контекста приложения, как и любой другой bean-компонент Spring. После создания bean-компонентов BeanPostProcessor контейнер Spring вызывает каждый из методов BeanPostProcessor postProcessBeforeInitialization и postProcessAfterInitialization для каждого экземпляра компонента, созданного контейнером Spring.

Пример BeanPostProcessor — проверка экземпляров компонентов

В приложении Spring вы можете проверить, правильно ли настроен экземпляр компонента, прежде чем он будет внедрен в зависимые компоненты или получит доступ к другим объектам в приложении. Давайте посмотрим, как мы можем использовать реализацию BeanPostProcessor, чтобы дать возможность каждому экземпляру bean-компонента проверять свою конфигурацию до того, как экземпляр bean-компонента становится доступным для зависимых bean-компонентов или других объектов приложения.

В следующем примере списка показан интерфейс InstanceValidator, который должен быть реализован компонентами, конфигурацию которых мы хотим проверить с помощью реализации BeanPostProcessor:

Пример листинга — интерфейс InstanceValidator

package sample.spring.chapter04.springbankapp.common;

public interface InstanceValidator {
  void validateInstance();
}

Интерфейс InstanceValidator определяет метод validateInstance, который проверяет, правильно ли инициализирован экземпляр компонента или нет. Мы скоро увидим, что метод validateInstance вызывается реализацией BeanPostProcessor.

В следующем примере списка показан класс FixedDepositDaoImpl, который реализует интерфейс InstanceValidator:

Пример листинга — класс FixedDepositDaoImpl

package sample.spring.chapter04.springbankapp.dao;

import org.apache.log4j.Logger;
import sample.spring.chapter04.springbankapp.common.InstanceValidator;

public class FixedDepositDaoImpl implements FixedDepositDao, InstanceValidator {

  private static Logger logger = Logger.getLogger(FixedDepositDaoImpl.class);

  private DatabaseConnection connection;

  public FixedDepositDaoImpl() {
    logger.info("FixedDepositDaoImpl's constructor invoked");
  }

  public void initializeDbConnection() {

  logger.info("FixedDepositDaoImpl's initializeDbConnection method invoked");
   connection = DatabaseConnection.getInstance();
  }

  @Override
  public void validateInstance() {
    logger.info("Validating FixedDepositDaoImpl instance");
     if(connection == null) {
     logger.error("Failed to obtain DatabaseConnection instance");
   }
  }
}

В приведенном выше листинге примера метод initializeDbConnection является методом инициализации, который извлекает экземпляр DatabaseConnection путем вызова статического метода getInstance класса DatabaseConnection. Атрибут соединения имеет значение null, если экземпляру FixedDepositDaoImpl не удается получить экземпляр DatabaseConnection. Если атрибут подключения имеет значение null, метод validateInstance регистрирует сообщение об ошибке, указывающее, что экземпляр FixedDepositDaoImpl инициализирован неправильно. Поскольку метод инициализации initializeDbConnection устанавливает значение атрибута соединения, метод validateInstance должен вызываться послеметод initializeDbConnection. В реальном сценарии разработки приложений, если экземпляр компонента не настроен правильно, метод validateInstance может предпринять некоторые корректирующие действия или вызвать исключительную ситуацию времени выполнения, чтобы остановить запуск приложения. Для простоты метод validateInstance регистрирует сообщение об ошибке, если экземпляр компонента не настроен правильно.

В следующем примере списка показан класс InstanceValidationBeanPostProcessor, который реализует интерфейс Spring BeanPostProcessor и отвечает за вызов метода validateInstance для вновь создаваемых bean-компонентов:

Пример листинга — класс InstanceValidationBeanPostProcessor

package sample.spring.chapter04.springbankapp.postprocessor;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.Ordered;

public class InstanceValidationBeanPostProcessor implements BeanPostProcessor, Ordered {
    private static Logger logger = Logger.getLogger(InstanceValidationBeanPostProcessor.class);
    private int order;

    public InstanceValidationBeanPostProcessor() {
        logger.info("Created InstanceValidationBeanPostProcessor instance");
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName)
            throws BeansException {
        logger.info("postProcessBeforeInitialization method invoked");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName)
            throws BeansException {
        logger.info("postProcessAfterInitialization method invoked");
        if (bean instanceof InstanceValidator) {
            ((InstanceValidator) bean).validateInstance();
        }
        return bean;
    }

    public void setOrder(int order) {
        this.order = order;
    }

    @Override
    public int getOrder() {
        return order;
    }
}

В приведенном выше примере показано, что класс InstanceValidationBeanPostProcessor реализует интерфейсы Spring BeanPostProcessor и Ordered. Метод postProcessBeforeInitialization просто возвращает экземпляр компонента, переданный методу. В методе postProcessAfterInitialization, если обнаружено, что экземпляр компонента имеет тип InstanceValidator, вызывается метод validateInstance экземпляра компонента. Это означает, что если бин реализует интерфейс InstanceValidator, InstanceValidationBeanPostProcessor вызывает метод validateInstance экземпляра бина после вызова метода инициализации экземпляра бина контейнером Spring.

Интерфейс Ordered определяет метод getOrder, который возвращает целочисленное значение. Целочисленное значение, возвращаемое методом getOrder, определяет приоритет реализации BeanPostProcessor по отношению к другим реализациям BeanPostProcessor, настроенным в XML-файле контекста приложения. BeanPostProcessor с более высоким значением порядка рассматривается с более низким приоритетом и выполняется после выполнения реализаций BeanPostProcessor с более низким значением порядка.

В следующем примере списка показаны определения компонентов для класса InstanceValidationBeanPostProcessor:

Пример листинга — определение компонента InstanceValidationBeanPostProcessor

<bean class="…...springbankapp.postprocessor.InstanceValidationBeanPostProcessor">

  <property name="order" value="1" />
</bean>

В приведенном выше определении компонента атрибут id элемента <bean> не указан, поскольку мы обычно не хотим, чтобы InstanceValidationBeanPostProcessor являлся зависимостью от любого другого компонента. Элемент <property> устанавливает значение свойства order в 1.

Вы можете скачать пример кода для этой статьи здесь . Чтобы запустить пример, выполнить основной метод SpringBankApp класса.