在 Spring bean 有条件地设置属性值时,SpEL 条件运算符未按预期进行评估(使用 XML 配置)

Posted

技术标签:

【中文标题】在 Spring bean 有条件地设置属性值时,SpEL 条件运算符未按预期进行评估(使用 XML 配置)【英文标题】:While setting property value conditionally on a Spring bean, SpEL conditional operator not evaluating as expected (using XML config) 【发布时间】:2019-12-03 21:43:18 【问题描述】:

在 Spring 批处理中,我需要根据从作业参数传递的标志有条件地在 bean 上注入属性。 例如如果作业参数“ISCAR”为“true”,我需要将字符串“Car.xsd”作为属性传递,否则为“Bus.xsd”。 我在哪里做错了?

这是我尝试过的 - 试试#1

   <property name="schemaFileName" value="# jobParameters['ISCAR'] == 'true' ? 'Car.xsd : Bus.xsd'" />

给:

java.lang.IllegalStateException:无法绑定到占位符: jobParameters['ISCAR'] == 'true' ? 'Car.xsd' : 'Bus.xsd'

尝试#2

<property name="schemaFileName" value="# #jobParameters['ISCAR'] == 'true' ? 'Car.xsd' : 'Bus.xsd'" />

给:

原因:java.lang.IllegalStateException:无法绑定到 占位符:真的? 'Car.xsd' : 'Bus.xsd'

尝试#3

<property name="schemaFileName" value="$ #jobParameters['ISCAR'] == 'true' ? 'Car.xsd' : 'Bus.xsd'" />

给:

使用单引号计算为 'Bus.xsd',即使条件 是真的,Car.xsd 是预期的

这是用作 tasklet 的 bean 的 XML 配置 -

 <batch:step id="validateXMLSchema" abstract="true">
         <batch:tasklet ref="xmlSchemaValidator" />
    </batch:step>

这里是设置Job参数的Java sn-p

JobParametersBuilder paramBuilder = new JobParametersBuilder();
paramBuilder.addString("ISCAR", "true");

编辑:添加堆栈跟踪

JobExecution:id=159480,startTime=Thu Jul 25 14:10:24 EDT 2019, endTime=2019 年 7 月 25 日星期四 14:10:25 EDT,lastUpdated=7 月 25 日星期四 14:10:25 EDT 2019,状态=失败, exitStatus=exitCode=FAILED;exitDescription=org.springframework.beans.factory.BeanCreationException: 创建具有名称的 bean 时出错 'lazyBindingProxy.xmlSchemaValidator#sysinit' 在类路径中定义 资源[xxx-job-detail-context.xml]:bean初始化失败; 嵌套异常是 java.lang.IllegalStateException: 无法绑定到 占位符:jobParameters.getString('ISCAR')=='true' ? '汽车.xsd': 'Bus.xsd' 在 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:527) 在 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456) 在 org.springframework.beans.factory.support.AbstractBeanFactory$2.getObject(AbstractBeanFactory.java:332) 在 org.springframework.batch.core.scope.StepScope.get(StepScope.java:137) 在 org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:328) 在 org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193) 在 org.springframework.batch.core.scope.util.PlaceholderTargetSource.getTarget(PlaceholderTargetSource.java:183) 在 org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:182) 在 com.sun.proxy.$Proxy11.beforeStep(未知来源) org.springframework.batch.core.listener.CompositeStepExecutionListener.beforeStep(CompositeStepExecutionListener.java:76) 在 org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:194) 在 org.springframework.batch.core.job.AbstractJob.handleStep(AbstractJob.java:348) 在 org.springframework.batch.core.job.SimpleJob.doExecute(SimpleJob.java:121) 在 org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:250) 在 org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:110) 在 org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:48) 在 org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:105) 在 org.springframework.batch.test.StepRunner.launchJob(StepRunner.java:167) 在 org.springframework.batch.test.StepRunner.launchStep(StepRunner.java:156) 在 org.springframework.batch.test.AbstractJobTests.launchStep(AbstractJobTests.java:218) 在 org.springframework.batch.test.AbstractJobTests.launchStep(AbstractJobTests.java:200) 在 mypackage.test.TestXXXJob.testXMLValidationStep(TestXXXJob.java:43) 在 sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 在 sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 在 java.lang.reflect.Method.invoke(Method.java:498) 在 org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) 在 org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) 在 org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) 在 org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) 在 org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74) 在 org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83) 在 org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72) 在 org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231) 在 org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57) 在 org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) 在 org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) 在 org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) 在 org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) 在 org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) 在 org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26) 在 org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) 在 org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71) 在 org.junit.runners.ParentRunner.run(ParentRunner.java:363) 在 org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174) 在 org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86) 在 org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) 在 org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:538) 在 org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:760) 在 org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:460) 在 org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:206) 引起:java.lang.IllegalStateException:无法绑定到 占位符:jobParameters.getString('ISCAR')=='true' ? '汽车.xsd': 'Bus.xsd' 在 org.springframework.batch.core.scope.util.PlaceholderTargetSource$1.convertIfNecessary(PlaceholderTargetSource.java:138) 在 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.convertForProperty(AbstractAutowireCapableBeanFactory.java:1411) 在 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1365) 在 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1118) 在 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:517) ... 50 更多 , job=[JobInstance: id=42213, JobParameters=[REQUESTFILEPATH=src/test/resources/testxml, REQUESTFILENAME=car_sample.xml,ISCAR=true, runCounter=0.029477961569429834], Job=[TestJob]]

【问题讨论】:

【参考方案1】:

我不知道你为什么引用 jobParameters 好像它是一张地图,我明白了

EL1027E: 不支持对类型“org.springframework.batch.core.JobParameters”的索引

这样。

这...

"#jobParameters.getString('ISCAR') == 'true' ? 'Car.xsd' : 'Bus.xsd'"

...对我来说很好用。

编辑

这是我的测试类:

@SpringBootApplication
public class So57204900Application 

    public static void main(String[] args) 
        SpringApplication.run(So57204900Application.class, args);
    

    @Value("#jobParameters.getString('ISCAR') == 'true' ? 'Car.xsd' : 'Bus.xsd'")
    private String param;


    @Bean
    public ApplicationRunner runner() 
        return args -> 
            System.out.println(param);
        ;
    

    @Bean
    public JobParameters jobParameters() 
        return new JobParametersBuilder().addString("ISCAR", "false").toJobParameters();
    


【讨论】:

对不起,这对我不起作用。我仍然收到 java.lang.IllegalStateException: Cannot bind to placeholder: jobParameters.getString('ISCAR') == 'true' 吗? 'Car.xsd' : 'Bus.xsd' 我用我的测试类编辑了答案;您可以编辑您的问题并显示完整的堆栈跟踪吗? 我已经用完整的 stacktrace @user:1240763 更新了这个问题 看起来您使用的是非常非常旧的 Batch 版本;该类 (PlaceholderTargetSource) 自 2013 年发布的 2.2 以来一直不存在。2.1 及更早版本使用 spring-framework 版本 2.5.6,它根本不支持 SpEL。 SpEL 是在 Spring 3.0 中引入的。您收到一条模糊消息的原因是 #... 不是公认的占位符。当前批处理版本为 4.1.2。 非常感谢@Gary。我们在应用程序中使用 Spring Batch 2.1.0.M1 和 Spring 3.1 以及基于 XML 的配置。不幸的是,版本的选择不是我能控制的。我在我的 pom.xml 中添加了 spring-expression 3.1 依赖项。但这也没有解决这个问题。为了解决这个问题,我现在将在 [at]BeforeStep 的 bean 中处理这个逻辑。

以上是关于在 Spring bean 有条件地设置属性值时,SpEL 条件运算符未按预期进行评估(使用 XML 配置)的主要内容,如果未能解决你的问题,请参考以下文章

Spring实战Spring中条件化地创建bean

当多个配置文件不活动时如何有条件地声明 Bean?

如何有条件地设置丰富的行:dataTable

手动注入bean时 , 根据条件注入bean

JSF Spring Bean 设置属性

有条件地在 JSF 组件标签中设置一个属性