14 PropertyOverrideConfigurer
14.1 简介
打个比方我们在bean容器中定义了一个beanA,其中有一个属性propB,对应值为valueB,但是我又希望在不更改bean定义的情况下希望Spring在实例化beanA时将对应的属性propB的值改为valueC,那么这个时候我们就可以使用PropertyOverrideConfigurer来实现这个效果了。PropertyOverrideConfigurer实现了BeanFactoryPostProcessor接口,其将在Spring加载完对应容器中所有的bean定义之后根据定义的属性来覆盖bean定义中既有属性的值。
来看一个示例,假设我们有如下定义的一个类Hello,其拥有一个int型的属性maxVal。
public class Hello {
private int maxVal;
public int getMaxVal() {
return maxVal;
}
public void setMaxVal(int maxVal) {
this.maxVal = maxVal;
}
}
在我们的bean定义中定义了一个Hello类型的bean,并指定了其属性maxVal的值为1。
<bean id="hello" class="com.app.Hello" p:maxVal="1"/>
那么这个时候我们在当前bean容器中定义一个PropertyOverrideConfigurer类型的bean,形式如下。
<bean class="org.springframework.beans.factory.config.PropertyOverrideConfigurer">
<property name="location" value="classpath:overrideConfig.properties"/>
</bean>
我们可以看到,其通过setLocation()方法注入了一个Resource,对应类路径下的overrideConfig.properties。接着来看一下该文件的内容。
hello.maxVal=10
该文件就简单的定义了一行,即一个属性。PropertyOverrideConfigurer在拿到了该属性后将在容器中所有的bean定义加载完成后,在容器中寻找id或name为hello的bean,然后将其属性maxVal的值置为10。对应的值将在实例化该bean时通过setMaxVal()方法进行赋值。这就是PropertyOverrideConfigurer干的事。其所使用的属性文件中属性名的定义形式是“beanName.prop1[.prop2[…]]”
,即属性名称至少由两部分组成,第一部分是目标bean的名称,第二部分是目标bean的属性,或属性的属性,它们之间以点进行连接。如“beanA.prop1.prop2=5”
即表示设置beanA的prop1的prop2为5,对应语义为beanA.getProp1().setProp2(5
)。
PropertyOverrideConfigurer只能用来替换文本类型的属性,像需要覆盖一个bean所关联的另一个bean这种需求就是不行,如果真有这种需求则推荐将其定义为一个属性变量,然后通过PropertyPlaceholderConfigurer进行替换。
14.2 加载属性的方式
PropertyOverrideConfigurer能够用来作为属性值覆盖的属性定义可以有多种形式,可以使用外部定义的属性文件,也可以使用PropertyOverrideConfigurer内部持有的属性定义。
14.2.1 外部文件
我们可以通过PropertyOverrideConfigurer的setLocation()方法和setLocations()方法来指定当前PropertyOverrideConfigurer需要使用的外部属性文件定义。其中setLocation()方法将用来指定单个文件,而setLocations()方法则可以用来指定一到多个文件。
<bean class="org.springframework.beans.factory.config.PropertyOverrideConfigurer">
<!-- 通过setLocations()方法指定需要使用的外部属性文件定义 -->
<property name="locations">
<array>
<value>classpath:overrideConfig.properties</value>
<value>classpath:overrideConfig2.properties</value>
</array>
</property>
</bean>
14.2.2 内部定义
通过PropertyOverrideConfigurer的setProperties()和setPropertiesArray()方法我们可以定义其使用的内部属性定义。其中setProperties()方法接收单个Properties对象,而setPropertiesArray()方法接收一到多个Properties对象。
<bean class="org.springframework.beans.factory.config.PropertyOverrideConfigurer">
<!-- 定义内部localProperties定义 -->
<property name="propertiesArray">
<array>
<ref bean="overrideConfig1"/>
</array>
</property>
</bean>
<!-- 定义Properties类型的bean -->
<bean id="overrideConfig1" class="java.util.Properties">
<constructor-arg>
<props>
<prop key="hello.maxVal">10</prop>
</props>
</constructor-arg>
</bean>
14.2.3 优先级
当一个PropertyOverrideConfigurer既指定了外部属性文件定义,又指定了内部属性定义时,如果某一个属性在外部属性文件和内部属性定义中同时存在,默认情况下外部属性文件定义的属性将覆盖内部属性定义。即如果外部属性文件定义指定了beanA.propB=1,而内部属性定义指定了beanA.propB=2,则最终使用的属性定义将是外部属性文件定义的beanA.propB=1。如果希望最终使用的是内部属性定义,即beanA.propB=2,则我们可以通过PropertyOverrideConfigurer的setLocalOverride()方法指定localOverride的值为true,即存在相同属性定义时内部属性定义将覆盖外部属性文件的定义。
<bean class="org.springframework.beans.factory.config.PropertyOverrideConfigurer">
<!-- 通过setLocation()方法指定需要使用的外部属性文件定义 -->
<property name="location" value="classpath:overrideConfig.properties"/>
<!-- 定义内部properties定义 -->
<property name="properties">
<props>
<prop key="hello.maxVal">50</prop>
</props>
</property>
<!-- 指定内部属性定义将覆盖外部属性文件定义的相同属性 -->
<property name="localOverride" value="true"/>
</bean>
14.3 指定beanName与属性之间的分隔符
beanName与属性之间的分隔符默认是点“.”。用户可以通过PropertyOverrideConfigurer的setBeanNameSeparator()方法来指定新的分隔符。
<bean class="org.springframework.beans.factory.config.PropertyOverrideConfigurer">
<!-- 定义内部properties定义 -->
<property name="properties">
<props>
<prop key="hello$maxVal">50</prop>
<prop key="hello$world.id">100</prop>
</props>
</property>
<!-- 指定beanName与属性之间的分隔符为$ -->
<property name="beanNameSeparator" value="$"/>
</bean>
如上所示,我们指定了beanName和属性之间的分隔符为“$”,所以当我们需要覆盖beanName为hello的maxVal的值时应该定义hello$maxVal=50
。但是属性的属性之间还是以点进行分隔,如上述示例中的hello$world.id=100
。
14.4 忽略文件未找到
默认情况下我们定义的外部属性文件不存在时将会抛出异常信息,如果用户不希望抛出异常信息,则可以通过setIgnoreResourceNotFound(true)
方法设置忽略文件未找到的情况。
<bean class="org.springframework.beans.factory.config.PropertyOverrideConfigurer">
<!-- 忽略外部属性文件不存在的异常信息 -->
<property name="ignoreResourceNotFound" value="true"/>
<!-- 该文件不存在,但是由于ignoreResourceNotFound设置为true将不会抛出异常 -->
<property name="location" value="afsf"/>
</bean>
14.5 忽略不存在的属性
默认情况下PropertyOverrideConfigurer使用的所有外部属性文件或内部属性定义的属性都将用来寻找对应的bean和属性进行属性值的覆盖。当存在非beanName.property
形式的属性定义或定义的bean或属性不存在时将抛出异常。如果用户不希望此种情况抛出异常,则可以通过setIgnoreInvalidKeys()
方法设置ignoreInvalidKeys属性值为true,已达到忽略不存在的属性的效果。
<bean class="org.springframework.beans.factory.config.PropertyOverrideConfigurer">
<!-- 忽略无效的属性定义,包括不存在的bean或属性等 -->
<property name="ignoreInvalidKeys" value="false"/>
<property name="properties">
<props>
<prop key="abc">1</prop>
<prop key="abc.adcdf">2</prop>
</props>
</property>
</bean>
14.6 指定加载顺序
我们可以在一个bean容器中同时定义多个PropertyOverrideConfigurer,这时候可以通过其setOrder()
方法指定当前PropertyOverrideConfigurer的处理顺序,对应值越小的越先处理。当多个PropertyOverrideConfigurer需要覆盖同一个bean的同一个属性时将取最后进行覆盖的那个PropertyOverrideConfigurer覆盖的值。
<bean class="org.springframework.beans.factory.config.PropertyOverrideConfigurer">
<!-- 指定处理顺序 -->
<property name="order" value="1"/>
</bean>
<bean class="org.springframework.beans.factory.config.PropertyOverrideConfigurer">
<!-- 指定处理顺序 -->
<property name="order" value="2"/>
</bean>
14.7 使用命名空间进行定义
PropertyOverrideConfigurer也支持在Spring的配置文件中通过引入对应的命名空间后使用对应的标签进行定义。如果需要使用命名空间定义,我们首先需要在Spring配置文件中引入context对应的命名空间,然后在其中定义一个property-override标签,这样Spring将自动创建一个PropertyOverrideConfigurer类型的bean定义。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:property-override/>
</beans>
然后我们可以通过property-override标签的属性来指定对应的参数。主要的可选参数如下。
- location:用于指定需要使用的外部资源文件的路径。多个文件路径之间使用逗号进行分隔。
- properties-ref:用于指定需要使用的内部属性定义对应的bean的名称。
- ignore-unresolvable:用于指定是否忽略不能解析的属性,默认为false。
- ignore-resource-not-found:用于指定是否忽略location指定路径的文件不存在的情况,默认为false。
- order:用于在定义当前PropertyOverrideConfigurer的处理顺序。
(注:本文是基于Spring4.1.0所写)
相关推荐
Spring是一个开源的Java平台,它是Java应用程序开发的一个综合和广泛的基础支持平台。Spring框架的目的是帮助Java开发者解决在开发应用程序时遇到的基础性问题,让开发者能够专注于业务逻辑的开发,而不必担心底层...
Spring系列——MVC框架整合.md
**Spring MVC —— 第一个应用程序** Spring MVC 是 Spring 框架的一个模块,主要用于构建 Web 应用程序。它提供了一种模型-视图-控制器(MVC)架构,简化了开发过程,使得开发者可以专注于业务逻辑而不必过于关心...
本文将深入探讨“Spring AOP——Schema”,这是Spring AOP的一种配置方式,通过XML schema定义切面和通知。 首先,我们需要理解AOP的基本概念。面向切面编程是一种编程范式,旨在提高软件的模块化程度,将关注点...
在"Quartz Spring整合——附带webservice Demo"的项目中,我们可以看到如何将这两个强大的工具结合在一起。这个Demo可能包含了一个使用Quartz调度器来触发Web服务调用的示例。Web服务(Webservice)是一种基于标准的...
SpringCloud为Zookeeper提供了一个名为`spring-cloud-starter-zookeeper`的启动器,允许开发者轻松地将Zookeeper集成到SpringBoot应用中。首先,我们需要在项目中引入依赖: ```xml <groupId>org.springframework...
【SpringCloud——声明性REST客户端(Feign)】 在分布式微服务架构中,服务之间的通信是至关重要的。Spring Cloud提供了一种优雅的方式,通过Feign客户端来实现这一目标。Feign是一个声明式的Web服务客户端,它...
Spring Cloud作为微服务解决方案的一部分,提供了多种服务发现工具,其中Consul是其中一个流行的选择。本文将深入探讨Spring Cloud如何整合Consul实现服务注册。 Consul是由HashiCorp公司开发的一款分布式系统服务...
【Spring 框架概述】 Spring 是一个广泛应用于企业级 Java 开发的开源框架,由 Rod Johnson 创建,旨在简化 Java EE 应用的复杂性。它以轻量级、低侵入式的设计理念,提供了全面的解决方案,涵盖从表现层到业务逻辑...
本篇文章将深入探讨Spring框架的一个重要特性——事件驱动模型。通过理解这一特性,开发者可以更好地利用Spring来实现应用间的通信和协调,提高系统的灵活性和可扩展性。 事件驱动模型是一种设计模式,它基于发布/...
Spring Cloud Sleuth是Spring Cloud生态系统的一部分,它实现了分布式追踪的标准——OpenTracing和Zipkin。通过集成Sleuth,开发者可以在不修改代码的情况下,轻松地在微服务架构中实现请求的全链路追踪。 二、核心...
我们从一个简单的容器开始,一步步的重构,最后实现一个基本的Spring框架的雏形,为了帮助我们更加深入的理解Spring的IoC...【SSH进阶之路】一步步重构容器实现Spring框架——彻底封装,实现简单灵活的Spring框架(十一)
**Spring Boot概述** Spring Boot是由Pivotal团队提供的全新框架,其设计目标是简化Spring应用的初始搭建以及开发过程。它基于"约定优于配置"的原则,通过提供开箱即用的功能,让开发者能够快速地创建独立运行的、...
Ribbon是一个客户端负载均衡器,它可以很好地控制HTTP和TCP客户端的行为。
《Spring开发指南——中文版》是由夏昕编著的一本针对Spring框架的中文教程,旨在帮助开发者更好地理解和应用Spring框架。Spring是Java平台上的一个核心框架,广泛应用于企业级应用开发,提供了一种全面的编程和配置...
标题中的“spring——第十四节素材.rar”表明这是一个关于Spring框架的教程材料,可能是课程的第14节内容。Spring是Java开发中最广泛使用的轻量级框架,它提供了丰富的功能来简化企业级应用的开发,包括依赖注入、...