评估 ${my.property} 作为 @Value 注释中的 SpEL 表达式
Evaluating ${my.property} as a SpEL expression within a @Value annotation
长话短说:
有没有一种方法可以在不使用转换器的情况下将 ${my.property}
产生的字符串解释为 @Value
注释中的 SpEL 表达式,例如像 @Value("#{${my.property}}
)?
我有一个抽象工厂(简化版),可以让我构建一些通用对象,这些对象是我系统配置的一部分。
@Component
public class Factory {
public Product makeVal(int x) { return new Product(5); }
}
为了更灵活,我想让用户在app.properties
文件中写SpEL表达式,这样工厂就可以直接访问了:
my.property = @Factory.makeVal(12)
现在,在 class 中需要这个 属性,为了实现我的目标,我编写了以下代码。
@Value("#{${my.property}}")
private Product obj;
我以为${my.property}
会被宏展开,然后被#{}
计算为对应的SpEL表达式,上例中的@Factory.makeVal(12)
。不幸的是,情况并非如此,加载 Spring 上下文导致错误,指出它无法将字符串(属性 的值 ${my.property}
)转换为目标类型Product
.
现在,我通过编写 class 实现 Converter<String, Product>
解决了这个问题,但它非常复杂,因为我需要在那里通过实例化 ExpressionParser
以编程方式将字符串评估为 SpEL 表达式等等。
但是有更简单的解决方案吗? @Value
注释中是否有单个 SpEL 表达式,让我可以简单地将 ${my.property}
本身评估为 SpEL 表达式,好吗?
也许只需将 属性 值中的 @Factory
替换为 factory
即可。我通过了这个测试:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { SpelTest.Config.class })
public class SpelTest
{
@Value("#{${my.property}}")
Product _product;
@Test
public void evaluating_spel_from_property_value() throws Exception
{
Assert.assertEquals(1234, _product.value);
}
@Component
public static class Factory
{
public Product makeVal(int x) { return new Product(x); }
}
public static class Product
{
public final int value;
public Product(final int value) { this.value = value; }
}
@Configuration
@ComponentScan(basePackageClasses = SpelTest.class)
public static class Config
{
@Bean
public Factory factory() { return new Factory(); }
@Bean
public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
final PropertySourcesPlaceholderConfigurer psc = new PropertySourcesPlaceholderConfigurer();
final MutablePropertySources sources = new MutablePropertySources();
sources.addFirst(new MockPropertySource()
.withProperty("my.property",
"factory.makeVal(1234)"));
psc.setPropertySources(sources);
return psc;
}
}
}
长话短说:
有没有一种方法可以在不使用转换器的情况下将 ${my.property}
产生的字符串解释为 @Value
注释中的 SpEL 表达式,例如像 @Value("#{${my.property}}
)?
我有一个抽象工厂(简化版),可以让我构建一些通用对象,这些对象是我系统配置的一部分。
@Component
public class Factory {
public Product makeVal(int x) { return new Product(5); }
}
为了更灵活,我想让用户在app.properties
文件中写SpEL表达式,这样工厂就可以直接访问了:
my.property = @Factory.makeVal(12)
现在,在 class 中需要这个 属性,为了实现我的目标,我编写了以下代码。
@Value("#{${my.property}}")
private Product obj;
我以为${my.property}
会被宏展开,然后被#{}
计算为对应的SpEL表达式,上例中的@Factory.makeVal(12)
。不幸的是,情况并非如此,加载 Spring 上下文导致错误,指出它无法将字符串(属性 的值 ${my.property}
)转换为目标类型Product
.
现在,我通过编写 class 实现 Converter<String, Product>
解决了这个问题,但它非常复杂,因为我需要在那里通过实例化 ExpressionParser
以编程方式将字符串评估为 SpEL 表达式等等。
但是有更简单的解决方案吗? @Value
注释中是否有单个 SpEL 表达式,让我可以简单地将 ${my.property}
本身评估为 SpEL 表达式,好吗?
也许只需将 属性 值中的 @Factory
替换为 factory
即可。我通过了这个测试:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { SpelTest.Config.class })
public class SpelTest
{
@Value("#{${my.property}}")
Product _product;
@Test
public void evaluating_spel_from_property_value() throws Exception
{
Assert.assertEquals(1234, _product.value);
}
@Component
public static class Factory
{
public Product makeVal(int x) { return new Product(x); }
}
public static class Product
{
public final int value;
public Product(final int value) { this.value = value; }
}
@Configuration
@ComponentScan(basePackageClasses = SpelTest.class)
public static class Config
{
@Bean
public Factory factory() { return new Factory(); }
@Bean
public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
final PropertySourcesPlaceholderConfigurer psc = new PropertySourcesPlaceholderConfigurer();
final MutablePropertySources sources = new MutablePropertySources();
sources.addFirst(new MockPropertySource()
.withProperty("my.property",
"factory.makeVal(1234)"));
psc.setPropertySources(sources);
return psc;
}
}
}