Справочное руководство по Spring 5: расширения контейнеров

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

Эта статья участвовала в третьем этапе курса «High Yield Update» тренировочного лагеря для создателей Nuggets. Подробнее см.:Dig Li Project | Идет третий этап тренировочного лагеря создателя, «написание» личного влияния.

Spring предоставляет ряд интерфейсов для расширения контейнера Spring. Давайте представим их один за другим.

Пользовательский компонент BeanPostProcessor

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

Интерфейс BeanPostProcessor определяет два метода:

	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

Этот метод вызывается перед вызовом методов инициализации контейнера (таких как InitializingBean.afterPropertiesSet() или любого объявленного метода инициализации) и после инициализации любого компонента.

	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

Этот метод вызывается после метода инициализации контейнера.

Можно настроить несколько BeanPostProcessors.Если вы хотите управлять порядком нескольких BeanPostProcessors, вы можете реализовать интерфейс Ordered для определения их порядка.

Хотя BeanPostProcessor автоматически обнаруживается через ApplicationContext, вы также можете зарегистрировать его вручную с помощью addBeanPostProcessor ConfigurableBeanFactory. Ручная регистрация аннулирует его Заказ, и порядок ручной регистрации будет иметь преимущественную силу.

Также обратите внимание, что программно зарегистрированные экземпляры BeanPostProcessor всегда обрабатываются перед регистрацией в качестве автоматически определяемых экземпляров и не получают никакого явного порядка.

Все экземпляры BeanPostProcessor и bean-компоненты, на которые непосредственно ссылаются эти экземпляры, создаются при запуске, и, поскольку автоматическое проксирование AOP реализовано как сам BeanPostProcessor, экземпляры BeanPostProcessor и bean-компоненты, на которые они напрямую ссылаются, не подходят для автоматического проксирования.

Вот пример вызова:

    <bean id="beanA" class="com.flydean.beans.BeanA"/>
    <bean id="beanB" class="com.flydean.beans.BeanB"/>

    <bean class="com.flydean.beans.InstantiationTracingBeanPostProcessor"/>

Реализация вызова:

    public static void main(final String[] args) throws Exception {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("bean-post-processor.xml");
        BeanA beanA = (BeanA) ctx.getBean("beanA");
        System.out.println(beanA);
    }

Метаданные пользовательской конфигурации BeanFactoryPostProcessor

Семантика интерфейса BeanFactoryPostProcessor аналогична семантике BeanPostProcessor с одним важным отличием: BeanFactoryPostProcessor работает с метаданными конфигурации компонента. То есть контейнер Spring IOC позволяет BeanFactoryPostProcessor считывать метаданные конфигурации и, возможно, изменять их до того, как контейнер создаст экземпляр любого компонента, отличного от экземпляра BeanFactoryPostProcessor.

BeanFactoryPostProcessor также можно настроить с несколькими и определить порядок выполнения, реализуя интерфейс Ordered. BeanFactoryPostProcessor определяет метод:

	void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

С помощью этого метода можно получить настраиваемую beanFactory для изменения определения компонента.

Spring предоставляет множество предопределенных постпроцессоров фабрики компонентов, таких как PropertyOverrideConfigurer и PropertyPlaceholderConfigurer. Ниже мы используем пример, чтобы проиллюстрировать, как его использовать.

Подстановка имени класса PropertyOverrideConfigurer

PropertyPlaceholderConfigurer в основном используется для чтения свойств из внешних файлов свойств для замены определенной конфигурации. Это позволяет пользователю, развертывающему приложение, настраивать свойства, зависящие от среды, такие как URL-адреса базы данных и пароли, без необходимости изменять их для контейнера или нескольких XML-файлов. мастер-файлы определений, тем самым увеличивая сложность или риск.

Ниже приведен XML-файл конфигурации:

    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations" value="classpath:jdbc.properties"/>
    </bean>

    <bean id="dataSource" destroy-method="close"
          class="com.flydean.beans.BasicDataSource">
        <property name="driverClassName" value="${jdbc.driverClassName}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

В этом примере показаны свойства, настраиваемые во внешнем файле свойств. Во время выполнения используйте PropertyPlaceholderConfigurer, чтобы заменить метаданные некоторыми свойствами в DataSource. Заменяемые значения указываются в качестве заполнителей в формате ${имя-свойства}, который соответствует стилям ant и log4j и JSP EL.

Фактическое значение берется из внешнего файла формата свойств Java:

jdbc.driverClassName=org.hsqldb.jdbcDriver
jdbc.url=jdbc:hsqldb:hsql://production:9002
jdbc.username=sa
jdbc.password=root

Переопределение свойства PropertyOverrideConfigurer

PropertyOverrideConfigurer можно использовать для переопределения значения свойства компонента по умолчанию или установки нового значения. Давайте посмотрим на пример:

    <bean class="org.springframework.beans.factory.config.PropertyOverrideConfigurer">
        <property name="locations" value="classpath:override.properties"/>
        <property name="properties">
            <value>beanOverride.url=com.something.DefaultStrategy</value>
        </property>
    </bean>
    <bean name="beanOverride" class="com.flydean.beans.BeanOverride"/>

Соответствующие классы:

@Data
public class BeanOverride {

    private String name="beanA";
    private String url="http://www.163.com";

}

Его свойства по умолчанию переопределены.

Пользовательская логика создания экземпляров с помощью FactoryBean

Интерфейс FactoryBean предоставляет 3 метода:

  • Object getObject(): возвращает экземпляр, созданный на заводе, который может использоваться совместно, в зависимости от того, является ли экземпляр одноэлементным или многоэкземплярным.
  • boolean isSingleton(): определяет, возвращает ли FactoryBean один экземпляр или несколько экземпляров.
  • Класс getObjectType(): возвращает тип, возвращаемый методом getObject(), или null, если тип заранее неизвестен.

Мы можем реализовать интерфейс FactoryBean для настройки логики реализации bean-компонентов.

public class BeanFactoryBean implements FactoryBean {

    @Resource
    private BeanA beanA;

    @Override
    public Object getObject() throws Exception {
        return beanA;
    }

    @Override
    public Class<?> getObjectType() {
        return BeanA.class;
    }
}

Вот его конфигурация:

    <context:annotation-config/>
    <bean id="beanA" class="com.flydean.beans.BeanA"/>

    <bean id="beanFactoryBean" class="com.flydean.beans.BeanFactoryBean"/>

как пользоваться?

    public static void main(final String[] args) throws Exception {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("bean-factory.xml");
        BeanFactoryBean beanFactoryBean = (BeanFactoryBean) ctx.getBean("&beanFactoryBean");
        System.out.println(beanFactoryBean.getObject());
        System.out.println(beanFactoryBean.getObjectType());

        BeanA beanA=(BeanA)ctx.getBean("beanFactoryBean");
        System.out.println(beanA);
    }

При вызове метода getbean() ApplicationContext добавляйте к идентификатору bean-компонента префикс амперсанда (&), когда необходимо запросить у контейнера фактический экземпляр FactoryBean, а не создаваемый им bean-компонент. Таким образом, для данного FactoryBean с идентификатором beanFactoryBean вызов getBean("beanFactoryBean") в контейнере возвращает bean-компонент, созданный FactoryBean, а вызов getBean("&beanFactoryBean") возвращает сам экземпляр FactoryBean.

Примеры в этом разделе могут относиться к:ioc-extend

Дополнительные руководства см.блог флайдина