Spring 3:禁用对bean属性值的SpEL评估?

Ste*_*hen 5 java spring javabeans

我们正在将我们的应用程序从Spring 2.5更新到3.0,并且我们遇到了新的SpEL评估bean属性的问题.

我们一直在一个模块中使用内部模板语法,遗憾的是它使用与SpEL相同的"#{xyz}"标记.我们有一些bean将包含这些表达式的字符串作为属性,但是spring假定它们是SpEL表达式,并在尝试实例化bean时抛出SpelEvaluationException.

例如

<bean id="templatingEngine" class="com.foo.TemplatingEngine">
   <property name="barTemplate" value="user=#{uid}&country=#{cty}"/>
</bean>
Run Code Online (Sandbox Code Playgroud)

是否可以禁用SpEL评估,理想情况是每个bean,但是对于整个应用程序上下文?

或者有没有办法逃避价值观?

谢谢,斯蒂芬

Chi*_*ang 5

通过调用传入的bean工厂setBeanExpressionResolver方法,完全禁用SpEL评估null。您可以定义一个BeanFactoryPostProcessor来做到这一点。

public class DisableSpel implements BeanFactoryPostProcessor {
    public void postProcessBeanFactory(
        ConfigurableListableBeanFactory beanFactory)
        throws BeansException
    {
        beanFactory.setBeanExpressionResolver(null);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后在应用程序上下文中定义此bean。

<bean class="com.example.spel.DisableSpel"/>
Run Code Online (Sandbox Code Playgroud)


Sea*_*oyd 3

那么你可以做的是重新定义表达式语言分隔符。

我想说,做到这一点的方法是通过一个特殊的 bean 来实现BeanFactoryPostProcessor(感谢 Jim Huang 的启发):

public class ExpressionTokensRedefiner implements BeanFactoryPostProcessor{

    private BeanExpressionResolver beanExpressionResolver;

    public void setBeanExpressionResolver(
        final BeanExpressionResolver beanExpressionResolver){
        this.beanExpressionResolver = beanExpressionResolver;
    }

    @Override
    public void postProcessBeanFactory(
        final ConfigurableListableBeanFactory beanFactory)
        throws BeansException{
        beanFactory.setBeanExpressionResolver(createResolver());
    }

    private String expressionPrefix = "${";
    private String expressionSuffix = "}";

    public void setExpressionPrefix(final String expressionPrefix){
        this.expressionPrefix = expressionPrefix;
    }
    public void setExpressionSuffix(final String expressionSuffix){
        this.expressionSuffix = expressionSuffix;
    }

    private BeanExpressionResolver createResolver(){
        if(beanExpressionResolver == null){
            final StandardBeanExpressionResolver resolver =
                new StandardBeanExpressionResolver();
            resolver.setExpressionPrefix(expressionPrefix);
            resolver.setExpressionSuffix(expressionSuffix);
            return resolver;
        } else{
            return beanExpressionResolver;
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

将其定义为一个 bean,如下所示:

<bean class="foo.bar.ExpressionTokensRedefiner">
    <property name="expressionPrefix" value="[[" />
    <property name="expressionSuffix" value="]]" />
</bean>
Run Code Online (Sandbox Code Playgroud)

或者像这样:

<!-- this will use the default tokens ${ and } -->
<bean class="foo.bar.ExpressionTokensRedefiner" />
Run Code Online (Sandbox Code Playgroud)

或使用自定义解析器:

<bean class="foo.bar.ExpressionTokensRedefiner">
    <property name="beanExpressionResolver">
        <bean class="foo.bar.CustomExpressionResolver" />
    </property>
</bean>
Run Code Online (Sandbox Code Playgroud)

现在您可以保持定义不变,如果您想使用 SpEL,请使用新的分隔符。

编辑:现在我测试了它,它确实有效。

<bean class="foo.bar.ExpressionTokensRedefiner">
    <property name="expressionPrefix" value="[[" />
    <property name="expressionSuffix" value="]]" />
</bean>


<bean class="foo.bar.FooFritz">
    <property name="fizz" value="[[ systemProperties['user.home'] ]]"></property>
    <property name="fozz" value="[[ systemProperties['java.io.tmpdir'] ]]"></property>
            <!-- this is what it would normally choke on -->
    <property name="fazz" value="#{ boom() }"></property>
</bean>
Run Code Online (Sandbox Code Playgroud)

测试代码:

final ConfigurableApplicationContext context =
    new ClassPathXmlApplicationContext("classpath:foo/bar/ctx.xml");
context.refresh();
final FooFritz fooFritz = context.getBean(FooFritz.class);
System.out.println(fooFritz.getFizz());
System.out.println(fooFritz.getFozz());
System.out.println(fooFritz.getFazz());
Run Code Online (Sandbox Code Playgroud)

输出:

/home/seanizer
/tmp
#{ 繁荣 () }