Spring核心——官配BeanFactoryPostProcessor

IoC功能扩展点这篇文章中介绍了BeanFactoryPostProcessor及其使用方法,本篇介绍Spring官方提供的典型BeanFactoryPostProcessor。

占位符参数替换——PropertyPlaceholderConfigurer

如果你的工程有很多配置内容放置到Java的标准配置文件*.properties中,当把Properties的内容整合到Spring中时就会用到PropertyPlaceholderConfigurer。PropertyPlaceholderConfigurer3个功能:

  1. 将配置中${property-name}格式的占位符换为加载的*.properties文件中的内容。
  2. 将配置中${property-name}格式的占位符替换为环境变量systemProperties(System.getProperty(key))中的内容。
  3. 如果文件和环境中有相同的key,按照规则对数据进行合并。

基本使用方法

PropertyPlaceholderConfigurer继承了配置BeanFactoryPostProcessor接口,在IoC开始初始化Bean之前修改对应BeanDefinition。在使用时我们直接向容器添加一个PropertyPlaceholderConfigurer即可:

<!-- 启用占位符替换需要引入PropertyPlaceholderConfigurer -->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <!-- 指定*.properties文件的路径 -->
    <property name="locations" value="classpath:project/config.properties"/>
</bean>

<!-- 替换Bean中的内容 -->
<bean id="A" class="x.y.z.User">
    <property name="name" value="${user.name}"/>
    <property name="address" value="${user.address}"/>
    <property name="age" value="${user.age}"/>
</bean>

对应的config.properties文件中的内容:

user.name='Alice'
user.address='China'
user.age=20

除了直接引入一个Bean,可以通过全局上下文配置启动这一项功能:

<context:property-placeholder location="classpath:project/config.properties"/>

设置环境变量加载行为

前面说了PropertyPlaceholderConfigurer除了会用*.properties文件中的参数去替换占位符的内容,还会使用环境变量(System.getProperty(key))中的参数去替换。如果一个参数在配置文件中和系统环境变量中都存在,那么默认会使用*.properties中的参数来替换配置中的占位符。可以使用PropertyPlaceholderConfigurer::systemPropertiesMode来修改这个行为。他接受3个参数:

  • PropertyPlaceholderConfigurer.SYSTEM_PROPERTIES_MODE_NEVER(0):从不加载环境变量中的参数。
  • PropertyPlaceholderConfigurer.SYSTEM_PROPERTIES_MODE_FALLBACK(1):优先使用*.properties文件中的变量,如果不存在再使用环境变量中的。
  • PropertyPlaceholderConfigurer.SYSTEM_PROPERTIES_MODE_OVERRIDE(2):优先使用环境变量中的参数。

可以这样设置:

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <!-- 优先使用环境变量中的参数 -->
    <property name="systemPropertiesMode" value="2"/>
</bean>

动态设置参数&动态替换类

除了通过环境变量和*.properties配置文件引入参数,还可以直接写在XML的配置上:

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <!-- 加载资源文件位置 -->
    <property name="locations">
        <value>classpath:myProject/config.properties</value>
    </property>
    <!-- 动态添加配置参数 -->
    <property name="properties">
        <value>define.runtime.class=x.y.z.A</value>
    </property>
</bean>
<!-- 动态加载一个类 -->
<bean id="a" class="${define.runtime.class}"/>

上面XML配置还展示了一个动态装载类的方法。

按命名规则注入——PropertyOverrideConfigurer

PropertyOverrideConfigurer就是在PropertyPlaceholderConfigurer的基础上扩展了一些功能节约一些写配置文件的时间。他可以让你不必在XML文件写占位符而直接注入数据。看下面的例子:

通过<bean>标签引入了PropertyOverrideConfigurer类,然后有一个独立的User单例,以及将Cpu、Ram、Graphics单例组合到Pc中。

<beans>
    <!-- 引入PropertyOverrideConfigurer -->
    <bean class="org.springframework.beans.factory.config.PropertyOverrideConfigurer"> 
        <property name="locations" value="classpath:xml/configoverride/config.properties"/>
    </bean>
    <!-- 配置Bean之间的组合关系 -->
    <bean id="user" class="chkui.springcore.example.xml.configoverride.User" />
    <bean id="cpu" class="chkui.springcore.example.xml.configoverride.entity.Cpu" />
    <bean id="ram" class="chkui.springcore.example.xml.configoverride.entity.Ram" />
    <bean id="graphics" class="chkui.springcore.example.xml.configoverride.entity.Graphics" />
    <bean id="pc" class="chkui.springcore.example.xml.configoverride.entity.Pc">
        <property name="cpu" ref="cpu"/>
        <property name="ram" ref="ram"/>
        <property name="graphics" ref="graphics"/>
    </bean>
</beans>

对应的*.properties配置是这样的:

user.name=Alice
user.address=china
user.age=20

pc.cpu.brand=AMD
pc.graphics.brand=Nvdia
pc.ram.brand=Kingston

Cpu类的结构:

package chkui.springcore.example.xml.configoverride.entity;
public class Cpu {
	private String brand;
	public String getBrand() {
		return brand;
	}
	public void setBrand(String brand) {
		this.brand = brand;
	}
}

这个时候PropertyOverrideConfigurer会根据容器中Bean的id或name来注入数据,比如*.properties配置中的"pc"就对应XML中的<bean id="pc">,接着pc中有一个域(成员变量)名为cpu那么它对应*.properties配置文件中"pc.cpu.",所以pc.cpu.brand=AMD的配置会告诉PropertyOverrideConfigurer向pc单例中的cpu实例的"brand"域注入数据"AMD"。

所以使用PropertyOverrideConfigurer运行之后,不需要在XML使用${property-name}这样的参数它会按照id或name的结构注入数据,此时user.getName() == "Alice"。如果类的关系是这个多层的结构一样可以根据Properties的结构注入数据,例如 pc.getPc().getBrand() == "AMD"。

例子的可执行代码见本人码云库中configoverride包

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏安恒网络空间安全讲武堂

Python编写渗透工具学习笔记二 | 0x03用python构建ssh僵尸网络

0x03用python构建ssh僵尸网络 1用pxssh暴力破解ssh密码 因为默认情况下只有linux有ssh服务,所以此脚本只适用于在linux下使用 靶机...

64770
来自专栏一枝花算不算浪漫

页面静态化技术Freemarker技术的介绍及使用实例.

43860
来自专栏开发与安全

linux系统编程之进程(三):exec系列函数和system函数

一、exec替换进程映象 在进程的创建上Unix采用了一个独特的方法,它将进程创建与加载一个新进程映象分离。这样的好处是有更多的余地对两种操作进行管理。当我们创...

31160
来自专栏大内老A

通过自定义ServiceHost实现对WCF的扩展[实例篇]

在《原理篇》中我们谈到了通过自定义ServiceHost对WCF进行扩展的本质,以及在IIS/WAS寄宿情况下ServiceHostFactory的作用。接下来...

29270
来自专栏逢魔安全实验室

微软公式编辑器系列漏洞分析(一):CVE-2017-11882

? 0x00 简介 CVE-2017-11882为Office内存破坏漏洞。攻击者可以利用漏洞以当前登录的用户的身份执行任意命令。所影响的组件是Office...

35050
来自专栏扎心了老铁

zookeeper curator选主(Leader)

在分布式系统设计中,选主是一个常见的场景。选主是一个这样的过程,通过选主,主节点被选择出来控制其他节点或者是分配任务。 选主算法要满足的几个特征: 1)各个节点...

75060
来自专栏老码农专栏

原 荐 ActFramework 发布 1.

23430
来自专栏人工智能LeadAI

ElasticSearch优化系列二:机器设置(内存)

预留一半内存给Lucence使用 一个常见的问题是配置堆太大。你有一个64 GB的机器,觉得JVM内存越大越好,想给Elasticsearch所有64 GB的内...

47340
来自专栏JackieZheng

Spring实战——缓存

缓存 提到缓存,你能想到什么?一级缓存,二级缓存,web缓存,redis…… 你所能想到的各种包罗万象存在的打着缓存旗号存在的各种技术或者实现,无非都是宣扬缓...

203100
来自专栏Danny的专栏

System.AccessViolationException”类型的未经处理的异常在 System.Data.dll 中发生。其他信息:尝试读取或写入受保护的内存。这通常指示其他内存已损坏。

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/huyuyang6688/article/...

16820

扫码关注云+社区

领取腾讯云代金券