maven占位符的使用(认真看完你就明白也就这么回事)

        在我们maven项目中经常用到占位符,除了spring配置文件中用到,java代码中也常常引用占位符,而到底占位符是怎么使用的,接下来我们进行简单的剖析!

(一)maven配置文件pom.xml中配置占位符

maven占位符默认的是${},也可以自己指定,如下:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-resources-plugin</artifactId>
    <version>2.5</version>
    <configuration>
        <useDefaultDelimiters>false</useDefaultDelimiters>
        <delimiters>
        <delimiter>$[*]</delimiter>
        </delimiters>
        <encoding>UTF-8</encoding>
    </configuration>
</plugin>

其中configuration中的设置就是指定占位符使用的方式:   

useDefaultDelimiters

是否使用默认占位符

delimiter

占位符
encoding占位符中value的编码方式

 

 

 

 

先举个简单例子:

如果applicationContext.xml配置文件里面配置如下:

<bean id="senderKafka" class="com.*.epp.kafka.SendKafka">
    <property name="metadataBookerList" value="$[metadata.broker.list]" />
    <property name="requestRequiredAcks" value="${request.required.acks}" />
    <property name="serializerClass" value="${serializer.class}" />
</bean>

我们给定一个app.properties参数文件如下:

metadata.broker.list = 10.27.25.161:9092,10.27.25.163:9093
request.required.acks = requestRequiredAcks
serializer.class = Serializer

运行build.xml之后,上面配置信息变成

<bean id="senderKafka" class="com.*.epp.kafka.SendKafka">
    <property name="metadataBookerList" value="10.27.25.161:9092,10.27.25.163:9093" />
    <property name="requestRequiredAcks" value="${request.required.acks}" />
    <property name="serializerClass" value="${serializer.class}" />
</bean>

通过$[]占位符,metadata.broker.list的值就被替换掉了,而另外两个由于默认的占位符失效了,所以没能被替换!,maven占位符在spring配置文件中替换内容并不需要在加载properties的前提下生效。

applicationContext.xml加载app.properties文件添加如下:

<context:property-placeholder location="app.properties"/>

再次执行build.xml,上面配置信息如下:

<bean id="senderKafka" class="com.*.epp.kafka.SendKafka">
    <property name="metadataBookerList" value="10.27.25.161:9092,10.27.25.163:9093" />
     <property name="requestRequiredAcks" value="${request.required.acks}" />
    <property name="serializerClass" value="${serializer.class}" />
</bean>

之前理解的是既然引用了properties文件,那么${}引用的的value也应该被替换,但是并没有被替换掉。

其实,pom中定义的占位符$[]是直接由maven执行处理了,而${request.required.acks}和${serializer.class}会由spring读取app.properties来赋值的,这个过程并不是在编译打包的过程中产生的,而是在系统运行时,这里先提前讲一下,在编译、打包的过程中,通过$[]替换的变量会被直接替换成值,而${}方式即使通过引入properties文件动态加载的并不会直接替换成值

(二)占位符在maven项目中的实际使用

  • spring配置文件通过加载properties文件使用默认占位符${}引入参数
  • 代码中通过@Value注解读取properties的属性值

如下图,在实际开发中不管是spring配置文件还是java代码中引用参数都不会直接引用父模块下的properties文件,而是通过在子模块下创建一个properties文件,创建的properties文件通过maven设置的占位符$[]引用父模块下properties文件,子模块下创建的properties文件用于该模块下动态数据的引用。如下图:

从图中还可得知:maven占位符除了可以引用properties文件中的参数,还可以引用pom文件下的properties参数

这一步主要是子模块需要的参数从父模块的properties文件引用到子模块的properties文件中!

另外要讲的就是(一)中结尾提到的在编译、打包的过程中,通过$[]替换的变量会被直接替换成值,而${}方式通过引入properties文件动态加载的并不会直接替换成值

main-settings.properties:

livecenter.serverURI=$[livecenter.serverURI]
live.serverURI=$[live.serverURI]

spring-impl.xml

<bean id="livecenterTemplate" class="com.suning.ottbss.client.PPTVSimpleJSONTemplate"
          parent="abstractHttp">
    <property name="serverURI" value="${livecenter.serverURI}"></property>
</bean>
<bean id="liveTemplate" class="com.suning.ottbss.client.PPTVSimpleJSONTemplate"
          parent="abstractHttp">
    <property name="serverURI" value="${live.serverURI}"></property>
</bean>

将main-settings.properties中的live.serverURL删除,不通过这种方式引入,直接在spring中通过maven占位符$[]直接引入vars下properties参数如下:

livecenter.serverURI=$[livecenter.serverURI]
<bean id="livecenterTemplate" class="com.suning.ottbss.client.PPTVSimpleJSONTemplate"
          parent="abstractHttp">
    <property name="serverURI" value="${livecenter.serverURI}"></property>
</bean>
<bean id="liveTemplate" class="com.suning.ottbss.client.PPTVSimpleJSONTemplate"
          parent="abstractHttp">
    <property name="serverURI" value="$[live.serverURI]"></property>
</bean>

编译之后如下:

livecenter.serverURI=http://livecenter.pptv.com/
<bean id="livecenterTemplate" class="com.suning.ottbss.client.PPTVSimpleJSONTemplate"
          parent="abstractHttp">
    <property name="serverURI" value="${livecenter.serverURI}"></property>
</bean>
<bean id="liveTemplate" class="com.suning.ottbss.client.PPTVSimpleJSONTemplate"
          parent="abstractHttp">
    <property name="serverURI" value="http://zhibo.pptv.com/"></property>
</bean>

从中可看出直接通过maven占位符引入的参数变量被替换了,而通过先引入本模块properties文件再通过${}引入变量并未被替换,通过打包结果也是如此,可见,在实际项目运行时,未被替换的变量还是通过动态引入的方式获取变量的。

 

再来进行一组测试:

vars下将live.serverURI=http://live.pptv.com/直接删除,将本模块properties文件main-setting.properties中直接赋值

live.serverURI=http://live.pptv.com/
livecenter.serverURI=http://livecenter.pptv.com/
<bean id="livecenterTemplate" class="com.suning.ottbss.client.PPTVSimpleJSONTemplate"
          parent="abstractHttp">
    <property name="serverURI" value="${livecenter.serverURI}"></property>
</bean>
<bean id="liveTemplate" class="com.suning.ottbss.client.PPTVSimpleJSONTemplate"
          parent="abstractHttp">
    <property name="serverURI" value="$[live.serverURI]"></property>
</bean>

编译之后如下:

<bean id="livecenterTemplate" class="com.suning.ottbss.client.PPTVSimpleJSONTemplate"
          parent="abstractHttp">
    <property name="serverURI" value="${livecenter.serverURI}"></property>
</bean>
<bean id="liveTemplate" class="com.suning.ottbss.client.PPTVSimpleJSONTemplate"
          parent="abstractHttp">
    <property name="serverURI" value="$[livecenter.serverURI]"></property>
</bean>

        由上面可以看出,不管properties放在哪里${livecenter.serverURI}在编译打包时均不会被替换成具体的值,此时$[livecenter.serverURI]也没有被替换成具体的值,说明maven占位符$[*]并未引用本模块的properties文件。这是什么原因呢??

主要是因为vars包下路径我们在pom文件中指定了,通过$[]引用的是pom文件下指定的properties,而模块中的properties与pom并无关系,仅是用于spring配置文件来加载而已,所以模块中的properties文件是在spring配置文件加载时起作用的,并非编译打包,编译打包时,我们会过滤资源文件,pom文件中配置了多环境下的vars路径,过滤主要是依据配置中引用的vars下的properties文件进行过滤,此时就是根据maven占位符进行替换的。

总而言之:目前的系统结构中,spring配置文件中${}占位符是spring工作时替换,$[]占位符是编译打包时根据vars下的配置文件替换的

(三) properties文件的使用

1、Spinrg的Bean XML定义中,可以通过${属性名}使用properties文件配置的值

首先,必须先加载properties配置文件,方式有两种,如下

方式一

<!-- 
	  用途1:Spring的xml配置文件中,可以通过${属性名}使用properties文件配置的值
	  用途2:可以使用@Value("${属性名}")注解读取properties文件配置的值,再给字段赋值
	         方法1:注解在字段上,给字段赋值
	         方法2:注解在字段的setter方法中赋值           
-->
<context:property-placeholder location="classpath:jdbc.properties"/>

方式二

<!-- 
	  用途1:Spring的xml配置文件中,可以通过${属性名}使用properties文件配置的值
	  用途2:可以使用@Value("${属性名}")注解读取properties文件配置的值,再给字段赋值
	         方法1:注解在字段上,给字段赋值
	         方法2:注解在字段的setter方法中赋值           
-->
<bean id="propertyConfigurer"
      class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
      <property name="location">
          <value>/WEB-INF/configs/sqlServer.properties</value>
      </property>
</bean>

可以清楚的看到,方式一,非常地简洁,但是如果要使用多个properties就可能实现不了,其实可以通过通配符实现,会有点麻烦。

接着,就可以在Bean的定义中,使用properties中的属性值,如下

<bean id="dataSource"
      class="org.springframework.jdbc.datasource.DriverManagerDataSource">
      <property name="driverClassName">
          <value>${jdbc.driver}</value>
      </property>
      <property name="url" >
          <value>${jdbc.url}</value>
      </property>
      <property name="username" >
          <value>${jdbc.user}</value>
      </property>
      <property name="password">
          <value>${jdbc.pwd}</value>
      </property>
</bean>

2、使用@Value注解读取properties文件配置的值,再给字段赋值

@Value注解是Spring 3.0 之后引入的新特性 

@Value的值有三种类型,#{} 、${} 和 #{'${}'} ,其实是#{}和${}这两种类型,#{'${}'} 这种是前两种的嵌套使用,下面分别介绍

1)  #{expression?:default value}

     #{} 花括号里面的是SpEL表达式(即Spring Expression Language),?: 前面的是表达式,?: 后面的是默认值,这种方式非常地灵活,可以直接取bean对象的字段值!SpEL表达式的介绍,请看官方参考资料http://docs.spring.io/spring/docs/current/spring-framework-reference/html/expressions.html

     但是,这种方式下,有个缺陷,那就是 properties配置文件中的属性名称不能带点,否则取不到值,会报错

如 file.uploadpath = E:\\360Downloads\\temp , 读取该属性值,就会报错,如下

@Value("#{prop.file.uploadpath}")
private String uploadPath;
Caused by: org.springframework.expression.spel.SpelEvaluationException: EL1008E: Property or field 'file' cannot be found on object of type 'java.util.Properties' - maybe not public?

要使用这种类型的Value值,实现方式有两种,如下

    方式一:

<!-- 
	    用途:可以使用@Value("#{prop.属性名}")注解读取properties文件配置的值,再给字段赋值
	         方法1:注解在字段上,给字段赋值
	         方法2:注解在字段的setter方法中赋值
	         注意:@Value("#{prop.属性名}") 中的 prop 是 注册的PropertiesFactoryBean的 Bean ID
-->
<bean id="prop" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
 	<property name="locations">
 		<array>
 			<value>classpath:fileupload.properties</value>
 		</array>
 	</property>
</bean>

方式二:

<!-- 
	    用途:可以使用@Value("#{prop.属性名}")注解读取properties文件配置的值,再给字段赋值
	         方法1:注解在字段上,给字段赋值
	         方法2:注解在字段的setter方法中赋值
	         注意:@Value("#{prop.属性名}") 中的 prop 是 注册的PropertiesFactoryBean的 Bean ID
-->
<util:properties id="prop" location="classpath:fileupload.properties"/>

可以清楚的看到,方式二,非常地简洁,但是如果要使用多个properties就可能实现不了,其实可以通过通配符实现,会有点麻烦。

接下来,看demo

fileupload.properties文件:

name=zengyanhui
age=12

Test.java:

package edu.mvcdemo.service;
 
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
 
/**
 * @编写人: yh.zeng
 * @编写时间:2017-7-26 下午11:04:10
 * @文件描述: todo
 */
@Component("test")
@Scope("singleton")
public class Test {
	@Value("#{prop.name}")
	private String name;
	
	@Value("#{prop.age}")
	private String age;
	
	public String getName() {
		return name;
	}
 
	public void setName(String name) {
		this.name = name;
	}
 
	public String getAge() {
		return age;
	}
 
	public void setAge(String age) {
		this.age = age;
	}
	
}

SpringBeanUtilsTest.java:

package edu.mvcdemo.utils;
 
import edu.mvcdemo.service.Test;
import junit.framework.TestCase;
 
/**
 * @编写人: yh.zeng
 * @编写时间:2017-7-26 下午11:09:38
 * @文件描述: todo
 */
public class SpringBeanUtilsTest  extends TestCase{
 
	public void test1(){
		SpringBeanUtils.setFilePath("src/springCfg/applicationContext-base.xml");
		Test test = (Test) SpringBeanUtils.getBean("test");
		System.out.println("name="+test.getName());
		System.out.println("age="+test.getAge());
	}
	
}

程序运行结果:

[INFO][2017-07-27 23:50:59][AbstractApplicationContext:583] - Refreshing org.springframework.context.support.FileSystemXmlApplicationContext@b8d805: startup date [Thu Jul 27 23:50:59 CST 2017]; root of context hierarchy
[INFO][2017-07-27 23:50:59][XmlBeanDefinitionReader:317] - Loading XML bean definitions from file [D:\EclipseWorkspace\MavenSpringMvcDemo\src\springCfg\applicationContext-base.xml]
name=zengyanhui
age=12

2)${property:default value}

    ${}这种值,只用来读取properties配置文件中的属性值, :  前面的是属性名称,:  后面的是默认值。这种类型的值,却可以读取带点的属性值,如 file.uploadpath = E:\\360Downloads\\temp,可以使用@Value("${file.uploadpath}")读取

     要使用这种方式的Value,有两种实现方式,如下

     方式一:

<!-- 
	    用途1:Spring的xml配置文件中,可以通过${属性名}使用properties文件配置的值
	    用途2:可以使用@Value("${属性名}")注解读取properties文件配置的值,再给字段赋值
	           方法1:注解在字段上,给字段赋值
	           方法2:注解在字段的setter方法中赋值           
-->
<bean id="propertyConfigurer"  
      class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">  
      <property name="location">  
          <value>classpath:fileupload.properties</value>  
      </property>  
</bean>  

方式二:

<!-- 
	    用途1:Spring的xml配置文件中,可以通过${属性名}使用properties文件配置的值
	    用途2:可以使用@Value("${属性名}")注解读取properties文件配置的值,再给字段赋值
	           方法1:注解在字段上,给字段赋值
	           方法2:注解在字段的setter方法中赋值           
-->
<context:property-placeholder  location="classpath:fileupload.properties"/>

可以清楚的看到,方式二,非常地简洁,但是如果要使用多个properties就可能实现不了,其实可以通过通配符实现,会有点麻烦。

下面看demo:

package edu.mvcdemo.service;
 
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
 
/**
 * @编写人: yh.zeng
 * @编写时间:2017-7-26 下午11:04:10
 * @文件描述: todo
 */
@Component("test")
@Scope("singleton")
public class Test {
	@Value("${name}")
	private String name;
	
	@Value("${age}")
	private String age;
	
	public String getName() {
		return name;
	}
 
	public void setName(String name) {
		this.name = name;
	}
 
	public String getAge() {
		return age;
	}
 
	public void setAge(String age) {
		this.age = age;
	}
 
}

程序运行结果:

[INFO][2017-07-27 23:50:59][AbstractApplicationContext:583] - Refreshing org.springframework.context.support.FileSystemXmlApplicationContext@b8d805: startup date [Thu Jul 27 23:50:59 CST 2017]; root of context hierarchy
[INFO][2017-07-27 23:50:59][XmlBeanDefinitionReader:317] - Loading XML bean definitions from file [D:\EclipseWorkspace\MavenSpringMvcDemo\src\springCfg\applicationContext-base.xml]
name=zengyanhui
age=12

(3)#{'${}'}

    这种类型的Value值,是#{}里面嵌套${}使用,所以必须按照上述的(1)(2)两种类型的实现方式,配置properties文件,才可以使用这种方式的值

@Value("#{'${age}'}")
private String age;

下面贴一张工作中使用的方式,大家可以研究研究

  • 2
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值