3.8.2 使用BeanFactoryPostProcessor定制配置元数据

我们将要看到的下一个扩展点是“org.springframework.beans.factory.config.BeanFactoryPostProcessor”。这个接口的语义类似于BeanPostProcessor,其中一个主要区别是:BeanFactoryPostProcessor对 bean配置元数据操作;也就是说,Spring IoC容器允许BeanFactoryPostProcessor读取配置元数据,并可能在容器实例化(除BeanFactoryPostProcessor之外的任何)bean之前改变它。

你可以配置多个BeanFactoryPostProcessors,你可以通过设置orderproperty来控制这些BeanFactoryPostProcessor的执行顺序。但是,如果BeanFactoryPostProcessor实现了 Ordered接口,则只能设置此属性。如果你写自己的“BeanFactoryPostProcessor”,你应该考虑实现 Ordered接口。有关更多详细信息,请参阅BeanFactoryPostProcessorOrdered接口的javadoc。

[Note]
如果你想改变实际的bean 实例(即从配置元数据创建的对象),那么你需要使用一个BeanPostProcessor(如上所述第3.8.1节“ BeanPostProcessor“)。虽然在技术上可以使用BeanFactoryPostProcessor(例如,使用BeanFactory.getBean())中的bean实例,这样做会导致提前的bean实例化,违反标准容器生命周期。这可能导致负面的副作用,如绕过bean后处理。此外,BeanFactoryPostProcessors的作用域也是在各自的容器内。这仅在使用容器层次结构时才相关。如果你在一个容器中定义一个BeanFactoryPostProcessor,它只会应用于该容器中的bean定义。一个容器中的Bean定义不会被另一个容器中的BeanFactoryPostProcessor进行后置处理,即使这两个容器都是同一层次结构的一部分。

当在“ApplicationContext”中声明一个bean工厂后置处理器时,它会自动执行,以便将定义容器的配置元数据进行的更改应用。 Spring包括一些预定义的bean工厂后置处理器,例如PropertyOverrideConfigurerPropertyPlaceholderConfigurer。 例如,定制的BeanFactoryPostProcessor也可以用来注册自定义属性编辑器。

一个ApplicationContext自动检测到它里面实现BeanFactoryPostProcessor接口的任何bean并部署。 它使用这些bean作为bean工厂后置处理器,在适当的时间。 你可以像部署其他bean一样部署这些后置处理器bean。(即ApplicationContext自动探测BeanFactoryPostProcessor接口的实现类。容器使用这些bean作为bean工厂post-processors。可以像其他bean那样将post-processor部署在容器内。)

[Note]
BeanPostProcessors一样,你通常不想为延迟初始化配置BeanFactoryPostProcessors。 如果没有其他bean引用Bean(Factory)PostProcessor,后置处理器将不会被实例化。 因此,标记它的延迟初始化将被忽略,并且Bean(Factory)PostProcessor将被及时实例化,即使你在<beans/>元素的声明上将default-lazy-init属性设置为 true 。也不行

Example: the Class name substitution PropertyPlaceholderConfigurer

你使用PropertyPlaceholderConfigurer将bean的属性值使用标准的Java Properties格式定义在一个单独的文件中。这样可以将应用的自定义环境配置属性隔离出来,例如数据库URL和密码,而不需要修改容器的主XML定义文件或Java 代码文件的复杂性或风险。

考虑以下基于XML的配置元数据片段,其中定义了具有占位符值的“DataSource”。 该示例显示从外部Properties文件配置的属性。 在运行时,将一个PropertyPlaceholderConfigurer应用于将替换DataSource的某些属性的元数据。 要替换的值被指定为遵循Ant / log4j / JSP EL样式的${property-name}形式的 placeholder

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="locations" value="classpath:com/foo/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>

在标准java Properties格式文件中实际的值:

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

因此,字符串${jdbc.username}在运行时被替换为值'sa',这同样适用于与属性文件中的键匹配的其他占位符值。 PropertyPlaceholderConfigurer检查bean定义的大多数属性和属性中的占位符。 此外,可以自定义占位符前缀和后缀。

使用Spring 2.5中引入的context命名空间,可以使用专用配置元素配置属性占位符。 一个或多个位置可以在location属性中以逗号分隔的列表形式提供。

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

PropertyPlaceholderConfigurer不仅在你指定的Properties文件中寻找属性。 默认情况下,如果在指定的属性文件中找不到属性,它还会检查Java“System”属性。 你可以通过将configurer的systemPropertiesMode属性设置为以下三个支持的整数值之一来定制此行为:

    • never * (0):不检查系统属性
    • fallback * (1):如果在指定的属性文件中不可解析,请检查系统属性。 这是默认值。
    • override * (2) :首先检查系统属性,然后尝试指定的属性文件。 这允许系统属性覆盖任何其他属性源。

有关更多信息,请参阅PropertyPlaceholderConfigurerjavadocs。

[Tip]

你可以使用PropertyPlaceholderConfigurer来替换类名,当你必须在运行时选择一个特定的实现类时,这是有用的。 例如:

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="locations">
        <value>classpath:com/foo/strategy.properties</value>
    </property>
    <property name="properties">
        <value>custom.strategy.class=com.foo.DefaultStrategy</value>
    </property>
</bean>

<bean id="serviceStrategy" class="${custom.strategy.class}"/>

若类在运行时期间不能解析为合法类,ApplicationContext创建非延迟初始化bean的preInstantiateSingletons()期间抛错误

Example: the PropertyOverrideConfigurer

“PropertyOverrideConfigurer”是另一个bean工厂后置处理器,类似于PropertyPlaceholderConfigurer,但是与后者不同,原始定义可以设置默认值或者根本不设置值。 如果重写的“Properties”文件没有特定bean属性的条目,那么就使用默认的上下文定义。

注意,bean定义并不知道它会被重写,所以使用了重写配置在XML配置中并不直观。 在多个PropertyOverrideConfigurer实例为同一个bean属性定义不同的值的情况下,最后一个实例配置会生效。

Properties文件配置格式如下:

beanName.property=value

例如:

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

此示例文件可用于包含名为 dataSource 的bean的容器定义,该bean具有 driver url 属性。

还支持复合属性名称,只要路径(除了覆盖的最终属性)的每个组件都已为非空(可能由构造函数初始化)。 在此示例中...

foo.fred.bob.sammy=123
  1. foo bean的fred属性的bob属性的sammy属性设置为标量值123
[Note]
指定的重写值都是字面值; 它们不会转换为bean引用。 当XML bean定义中的原始值指定一个bean引用时,此约定也适用。

使用Spring 2.5中引入的context命名空间,可以使用专用配置元素配置属性覆盖:

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

results matching ""

    No results matching ""