Следующая которую мы рассмотрим, это точка расширения 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
С помощью пространства имен context
, представленного в Spring 2.5, можно настроить переопределение свойств с помощью специального элемента конфигурации, как показано в следующем примере:
<context:property-override location="classpath:override.properties"/>