Следующая которую мы рассмотрим, это точка расширения org.springframework.beans.factory.config.BeanFactoryPostProcessor. Семантика этого интерфейса аналогична семантике BeanPostProcessor, с одним существенным отличием: BeanFactoryPostProcessor работает с конфигурационными метаданными бина. То есть IoC-контейнер Spring позволяет BeanFactoryPostProcessor считывать конфигурационные метаданные и потенциально изменять их до того, как контейнер создаст экземпляры каких-либо бинов, помимо экземпляров BeanFactoryPostProcessor.

Можно сконфигурировать несколько экземпляров BeanFactoryPostProcessor, а также контролировать порядок запуска этих экземпляров BeanFactoryPostProcessor, установив свойство order. Однако вы можете установить это свойство только в том случае, если BeanFactoryPostProcessor реализует интерфейс Ordered. Если вы пишете свой собственный BeanFactoryPostProcessor, то следует рассмотреть реализацию интерфейса Ordered. Более подробную информацию см. в javadoc интерфейсов BeanFactoryPostProcessor и Ordered.

Если вы хотите изменить фактические экземпляры бинов (то есть объекты, которые создаются на основе конфигурационных метаданных), то необходимо использовать BeanPostProcessor (описанный ранее в разделе Настройка бинов с помощью BeanPostProcessor). Хотя технически возможно работать с экземплярами бинов внутри BeanFactoryPostProcessor (например, используя BeanFactory.getBean()), это приводит к преждевременному созданию экземпляра бина, что нарушает стандартный жизненный цикл контейнера. Это может вызвать негативные побочные эффекты, такие как обход пост-обработки бина.

Кроме того, экземпляры BeanFactoryPostProcessor привязаны к одному контейнеру. Способ актуален только в том случае, если вы используете иерархии контейнеров. Если BeanFactoryPostProcessor определен в одном контейнере, он применяется только к определениям бинов, находящихся в этом контейнере. Определения бинов, находящихся в одном контейнере, не обрабатываются экземплярами BeanFactoryPostProcessor в другом контейнере, даже если оба контейнера являются частью одной иерархии.

Постпроцессор фабрики бинов автоматически запускается, если он объявляется внутри ApplicationContext, для применения изменений к конфигурационным метаданным, определяющим контейнер. Spring содержит ряд предопределенных постпроцессоров фабрики бинов, такие как PropertyOverrideConfigurer и PropertySourcesPlaceholderConfigurer. Также можно использовать специальный BeanFactoryPostProcessor, например, для регистрации специальных редакторов свойств.

ApplicationContext автоматически определяет все развернутые в нем бины, которые реализуют интерфейс BeanFactoryPostProcessor. Он использует эти бины в качестве постпроцессоров фабрики бинов в соответствующий момент. Вы можете развернуть эти бины постпроцессора так же, как и любые другие бины.

Как и в случае с BeanPostProcessors, обычно не нужно конфигурировать BeanFactoryPostProcessorsдля отложенной инициализации. Если ни один другой бин не ссылается на Bean(Factory)PostProcessor, экземпляр этого постпроцессора вообще не будет создан. Таким образом, то, что он помечен для отложенной инициализации, будет проигнорировано, а экземпляр Bean(Factory)PostProcessor будет создал без задержек, даже если вы установите атрибут default-lazy-init в true при объявлении элемента <beans />.
Пример: Подстановка имени класса PropertySourcesPlaceholderConfigurer

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

Рассмотрим следующий фрагмент конфигурационных метаданных на основе XML, где определен источник данных DataSource плейсхолдерами:

<bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
    <property name="locations" value="classpath:com/something/jdbc.properties"/>
</bean>
<bean id="dataSource" destroy-method="close"
        class="org.apache.commons.dbcp.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>

В примере показаны свойства, сконфигурированные из внешнего файла Properties. Во время выполнения к метаданным применяется PropertySourcesPlaceholderConfigurer, который заменяет некоторые свойства DataSource. Значения для замены указываются как плейсхолдеры формы ${property-name}, что соответствует стилю Ant и log4j и JSP EL.

Фактические значения поступают из другого файла в стандартном формате Java Properties:

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

Поэтому строка ${jdbc.username} заменяется во время выполнения на значение 'sa', и то же самое относится к другим плейсхолдерам, которые соответствуют ключам в файле свойств. PropertySourcesPlaceholderConfigurer проверяет наличие плейсхолдеров в большинстве свойств и атрибутов определения бина. Кроме того, вы можете индивидуально настроить префикс и суффикс плейсхолдера.

С помощью пространства имен context, представленного в Spring 2.5, вы можете настраивать плейсхолдеры свойств с помощью выделенного элемента конфигурации. Вы можете указать одно или несколько местоположений в виде списка, разделенного запятыми, в атрибуте location, как показано в следующем примере:

<context:property-placeholder location="classpath:com/something/jdbc.properties"/>

PropertySourcesPlaceholderConfigurer не только ищет свойства в указанном вами файле Properties. По умолчанию, если ему не удается найти свойство в указанных файлах свойств, он проверяет свойства Spring Environment и обычные свойства Java System.

Можно использовать PropertySourcesPlaceholderConfigurer для подстановки имен классов, что иногда полезно, если необходимо выбрать конкретный класс реализации во время выполнения. В следующем примере показано, как это сделать:

<bean class="org.springframework.beans.factory.config.PropertySourcesPlaceholderConfigurer">
    <property name="locations">
        <value>classpath:com/something/strategy.properties</value>
    </property>
    <property name="properties">
        <value>custom.strategy.class=com.something.DefaultStrategy</value>
    </property>
</bean>
<bean id="serviceStrategy" class="${custom.strategy.class}"/>

Если класс не может быть разрешен во время выполнения в допустимый класс, разрешение бина не происходит, когда он должен быть создан, то есть во время фазы preInstantiateSingletons() ApplicationContext для non-lazy-init бина.

Пример: PropertyOverrideConfigurer

PropertyOverrideConfigurer, еще один постпроцессор фабрики бинов, похож на PropertySourcesPlaceholderConfigurer, но в отличие от последнего, исходные определения могут иметь значения по умолчанию или вообще не иметь значений для свойств бина. Если в переопределяющем файле Properties нет записи для определенного свойства бина, используется контекстное определение по умолчанию.

Обратите внимание, что определение бина не знает о том, что оно переопределено, поэтому из файла определения XML не сразу очевидно, что используется конфигуратор переопределения. В случае нескольких экземпляров PropertyOverrideConfigurer, которые определяют различные значения для одного и того же свойства бина, последний побеждает благодаря механизму переопределения.

Строки конфигурации файла свойств имеют следующий формат:

beanName.property=value

В следующем листинге приведен пример формата:

dataSource.driverClassName=com.mysql.jdbc.Driver
dataSource.url=jdbc:mysql:mydb

Этот файл-пример можно использовать с определением контейнера, содержащего бин под названием dataSource, который имеет свойства driver и url.

Составные имена свойств также поддерживаются, если все компоненты пути, кроме конечного переопределяемого свойства, уже не являются пустыми (null) (предположительно инициализированы конструкторами). В следующем примере свойство sammy свойства bob свойства fred бина tom установлено в скалярное значение 123:

tom.fred.bob.sammy=123
Указанные значения переопределения всегда являются литеральными значениями. Их нельзя преобразовать в ссылки на бины. Это соглашение также применяется, если исходное значение в определении бина на основе XML задает ссылку на бин.

С помощью пространства имен context, представленного в Spring 2.5, можно настроить переопределение свойств с помощью специального элемента конфигурации, как показано в следующем примере:

<context:property-override location="classpath:override.properties"/>