运行时值注入Bean

来源:互联网 发布:电缆价格计算软件 编辑:程序博客网 时间:2024/06/10 00:45

运行时值注入Bean

bean装配的另外一个方面指的是将一个值注入到bean的属性或者构造器参数中。但如果是下面这种装配bean的话注入的值就是硬编码了。

@Beanpublic Student student() {    return new Student(        "zhengjunming",        "3116005120");}

使用XML装配bean也同样是硬编码

<bean id="student" class="com.zheng.spring.Student"      c:_name="zhengjunming"      c:_studentId="3116005120" />

有时候硬编码是可以的,但有的时候,我们可能会希望避免硬编码值,而是想让这些值在运行时再确定。为了实现这些功能,Spring提供了两种在运行时求值的方式:

  1. 属性占位符(Property placeholder)。
  2. Spring表达式语言(SpEL)。

注入外部的值

属性占位符

使用@PropertySource注解和Environment

这种方法就在一定程度上消除了硬编码的情况

package com.zheng.spring;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.PropertySource;import org.springframework.core.env.Environment;@Configuration@PropertySource("classpath:student.properties") // 声明属性源public class TestProperty {    private final Environment env;    @Autowired    public TestProperty(Environment env) {        this.env = env;    }    @Bean    public Student student() {        // 利用Environment对象检索属性值        return new Student(env.getProperty("student.name"),                env.getProperty("student.id"));    }}

student.properties内容如下

student.name=zhengjunmingstudent.id=3116005120

深入Environment

getProperty()方法由四个重载的形式

String getProperty(String key);String getProperty(String key, String defaultValue);<T> T getProperty(String key, Class<T> type);<T> T getProperty(String key, Class<T> type, T defaultValue);

我们首先看第二个重载的方法,根据参数我们可以很清楚的知道,如果指定属性不存在的时候,会使用一个默认值defaultValue。

@Beanpublic Student student() {    // 利用Environment对象检索属性值    return new Student(env.getProperty("student.name", "zheng"),           env.getProperty("student.id", "3116005120"));}

当我们希望得到的是Integer类型或者其他类型而不是String类型,我们就可以用到第三个和第四个的getProperty()方法。

int id = env.getProperty("student.id", Integer.class, 3116005120);

Environment还提供了另外几个与属性相关的方法:

  1. getRequiredProperty()方法:属性必须定义:不然抛出IllegalStateException异常。
@Beanpublic Student student() {    return new Student(env.getRequiredProperty("student.name"),           env.getRequiredProperty("student.id"));}
  1. containsProperty()方法:检查某个属性是否存在。
  2. getPropertyAsClass()方法:将属性解析为类

除了属性相关的功能以外,Environment还提供了一些方法来检查哪些profile处于激活状态:

  1. String[] getActiveProfiles():返回激活profile名称的数组;
  2. String[] getDefaultProfiles():返回默认profile名称的数组;
  3. boolean acceptsProfiles(String… profiles):如果environment支持给定profile的话,就返回true。

解析属性占位符

解析占位符的形式为使用“${ … }”包装的属性名称。

在XML中解析占位符

<bean id="student" class="com.zheng.spring.Student"      c:_name="${student.name}"      c:_id="${student.id}" />

如果我们依赖于组件扫描和自动装配来创建和初始化应用组件的话,那么就没有指定占位符的配置文件或类了。在这种情况下,我们可以使用@Value注解。

public Student(@Value("$student.name") String name,               @Value("$student.id") String id) {    this.name = name;    this.id = id;}

为了使用占位符,我们必须要配置一个PropertyPlaceholderConfigurer beanPropertySourcesPlaceholderConfigurer bean。从Spring 3.1开始,推荐使用PropertySourcesPlaceholderConfigurer,因为它能够基于Spring Environment及其属性源来解析占位符。

@Beanpublic PropertySourcesPlaceholderConfigurer placeholderConfigurer() {    return new PropertySourcesPlaceholderConfigurer();}

对应的XML配置如下

<context:property-placeholder />

使用Spring表达式语言(SpEL)进行装配

SpEL拥有很多特性,包括:

  • 使用bean的ID来引用bean;
  • 调用方法和访问对象的属性;
  • 对值进行算术、关系和逻辑运算;
  • 正则表达式匹配;
  • 集合操作。

SpEL表达式要放到“#{ … }”之中,例如#{T(System).currentTimeMillis()}: T()表达式会将java.lang.System视为Java中对应的类型,因此可以调用其static修饰的currentTimeMillis()方法。

SpEL表达式也可以引用其他的bean或其他bean的属性。例如,如下的表达式会计算得到ID为student的bean的name属性:#{student.name}

通过systemProperties对象引用系统属性:#{systemProperties['student.name']}

如果通过组件扫描创建bean的话,在注入属性和构造器参数时,我们可以使用@Value注解。

public Student(@Value("#{systemProperties['student.name']") String name,               @Value("#{systemProperties['student.id']") String id) {    this.name = name;    this.id = id;}

引用bean、属性和方法

student为bean的ID

  • 引用bean:#{student}
  • 引用属性:#{student.name}
  • 引用方法:#{student.getName()}
  • 操作方法返回值:#{student.getName().toUpperCase()} 。则利用了返回值,然后使字符串变为大写。
  • 若上面返回值为null将引发空指针异常,为了避免这种情况发生,可以使用类型安全的运算符:#{student.getName()?.toUpperCase()}。如果为null将不会引用toUpperCase的方法,只会用到返回值null。

在表达式中使用类型

要在SpEL中访问类作用域的方法和常量的话,要依赖T()这个运算符。例如:#{T(java.lang.Math)}

T()运算符的结果会是一个Class对象。能够访问目标类型的静态方法和常量。例如:#{T(java.lang.Math).PI}

用来操作表达式值的SpEL运算符

运 算 符 类 型 运 算 符 算 术 运 算
    、 - 、 * 、 / 、 % 、 ^
比较运算 < 、 > 、 == 、 <= 、 >= 、 lt 、 gt 、 eq 、 le 、 ge 逻辑运算 and 、 or 、 not 、│ 条件运算 ?: (ternary) 、 ?: (Elvis) 正则表达式 matches
原创粉丝点击