Spring 集成 Groovy 脚本和 SpEL
Spring Integration Groovy Script and SpEL
我正尝试在我的 spring 集成配置中针对特定场景使用 Groovy 脚本。有几个错误我无法解决或超出我的理解范围。请原谅,因为我不太精通 groovy 脚本。
我的库中有 spring-integration-groovy-3.0.2.RELEASE.jar
。
下面是我的 spring 集成配置:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:int="http://www.springframework.org/schema/integration" xmlns:context="http://www.springframework.org/schema/context"
xmlns:stream="http://www.springframework.org/schema/integration/stream"
xmlns:int-groovy="http://www.springframework.org/schema/integration/groovy" xmlns:lang="http://www.springframework.org/schema/lang"
xsi:schemaLocation="http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-3.2.xsd
http://www.springframework.org/schema/integration/groovy http://www.springframework.org/schema/integration/groovy/spring-integration-groovy-3.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/stream http://www.springframework.org/schema/integration/stream/spring-integration-stream.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- Works fine: Using service-activator and SpEL to call a java bean.method(params) -->
<int:chain input-channel="requestChannel" output-channel="responseChannel">
<int-xml:xslt-transformer xsl-templates="BookingClassFilter_Template" result-transformer="resultToDOMSource" />
<int:service-activator expression="@errorDetectionUtil.checkAndThrowExceptionOnError(#root)" />
</int:chain>
// Note: I want to replace the above int:chain with the below. Only the below section appears in my final configuration file deployed. The above int:chain is only as an example for Q&A.
<!-- NOT WORKING: Using Groovy script -->
<int:chain id="businessLayerResponse" input-channel="requestChannel" output-channel="responseChannel">
<int-xml:xslt-transformer xsl-templates="BookingClassFilter_Template" result-transformer="resultToDOMSource" />
<int-groovy:script>
def valBool = errorDetectionUtil.hasErrors(payload)
if(valBool) throw new AppException(#root)
return #root
</int-groovy:script>
</int:chain>
</beans>
下面是我的Javaclass:
import javax.xml.transform.dom.DOMSource;
@Component("errorDetectionUtil")
public class ErrorDetectionUtil {
public boolean hasErrors(DOMSource domSource) {
double countDbl = (double) errorsCounter.evaluate(domSource.getNode(), XPathConstants.NUMBER);
return ((int) countDbl > 0)
}
public Message<?> checkAndThrowExceptionOnError(Message<?> message) throws AppException {
if (hasErrors((DOMSource) message.getPayload())) {
throw new AppException(message);
}
return message;
}
}
// AppException extends org.springframework.integration.MessagingException
我不确定我做错了什么。下面是我在启动应用程序服务器时看到的异常堆栈跟踪。
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.integration.handler.MessageHandlerChain#13': Cannot create inner bean 'businessLayerResponse$child#2.handler' of type [org.springframework.integration.groovy.GroovyScriptExecutingMessageProcessor] while setting bean property 'handlers' with key [2]; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'businessLayerResponse$child#2.handler': Error setting property values; nested exception is org.springframework.beans.NotWritablePropertyException: Invalid property 'componentName' of bean class [org.springframework.integration.groovy.GroovyScriptExecutingMessageProcessor]: Bean property 'componentName' is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter?
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveInnerBean(BeanDefinitionValueResolver.java:282)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:121)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveManagedList(BeanDefinitionValueResolver.java:353)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:154)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1387)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1128)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:458)
at org.springframework.beans.factory.support.AbstractBeanFactory.getObject(AbstractBeanFactory.java:295)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:626)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479)
at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:389)
at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:294)
at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:112)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4729)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5167)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:725)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:701)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:717)
at org.apache.catalina.startup.HostConfig.deployDescriptor(HostConfig.java:586)
at org.apache.catalina.startup.HostConfig$DeployDescriptor.run(HostConfig.java:1750)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
at java.util.concurrent.FutureTask.run(FutureTask.java:262)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'businessLayerResponse$child#2.handler': Error setting property values; nested exception is org.springframework.beans.NotWritablePropertyException: Invalid property 'componentName' of bean class [org.springframework.integration.groovy.GroovyScriptExecutingMessageProcessor]: Bean property 'componentName' is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter?
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1423)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1128)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:458)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveInnerBean(BeanDefinitionValueResolver.java:271)
... 30 more
Caused by: org.springframework.beans.NotWritablePropertyException: Invalid property 'componentName' of bean class [org.springframework.integration.groovy.GroovyScriptExecutingMessageProcessor]: Bean property 'componentName' is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter?
at org.springframework.beans.BeanWrapperImpl.setPropertyValue(BeanWrapperImpl.java:1042)
at org.springframework.beans.BeanWrapperImpl.setPropertyValue(BeanWrapperImpl.java:902)
at org.springframework.beans.AbstractPropertyAccessor.setPropertyValues(AbstractPropertyAccessor.java:75)
at org.springframework.beans.AbstractPropertyAccessor.setPropertyValues(AbstractPropertyAccessor.java:57)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1420)
... 34 more
<groovy:script>
本身不是组件。它只能反映其他EIP特定组件的行为。
那么,您的 <service-activator>
也会在那里。但是您使用 <script>
.
而不是 expression
#root
变量是 SpEL 的一部分,正好是 Message<?>
。对于脚本,它被拆分为 payload
和 headers
变量。是的,你应该在没有 #
的情况下使用它们。
正确的,您的 errorDetectionUtil
在 Groovy 脚本中可用,因为 Spring 集成 3.0。
对我的 spring 集成进行以下更改解决了问题:
<int:chain id="businessLayerResponse" input-channel="requestChannel" output-channel="responseChannel">
<int-xml:xslt-transformer xsl-templates="BookingClassFilter_Template" result-transformer="resultToDOMSource" />
<int:service-activator>
<int-groovy:script>
def valBool = errorDetectionUtil.hasErrors(payload)
def message = org.springframework.integration.support.MessageBuilder.withPayload(payload).copyHeaders(headers).build()
if(java.lang.Boolean.valueOf(valBool)) {
throw new x.y.z.AppException(message)
}
return message
</int-groovy:script>
</int:service-activator>
</int:chain>
注意:脚本中需要完全限定 java class 个名称。
我正尝试在我的 spring 集成配置中针对特定场景使用 Groovy 脚本。有几个错误我无法解决或超出我的理解范围。请原谅,因为我不太精通 groovy 脚本。
我的库中有 spring-integration-groovy-3.0.2.RELEASE.jar
。
下面是我的 spring 集成配置:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:int="http://www.springframework.org/schema/integration" xmlns:context="http://www.springframework.org/schema/context"
xmlns:stream="http://www.springframework.org/schema/integration/stream"
xmlns:int-groovy="http://www.springframework.org/schema/integration/groovy" xmlns:lang="http://www.springframework.org/schema/lang"
xsi:schemaLocation="http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-3.2.xsd
http://www.springframework.org/schema/integration/groovy http://www.springframework.org/schema/integration/groovy/spring-integration-groovy-3.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/stream http://www.springframework.org/schema/integration/stream/spring-integration-stream.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- Works fine: Using service-activator and SpEL to call a java bean.method(params) -->
<int:chain input-channel="requestChannel" output-channel="responseChannel">
<int-xml:xslt-transformer xsl-templates="BookingClassFilter_Template" result-transformer="resultToDOMSource" />
<int:service-activator expression="@errorDetectionUtil.checkAndThrowExceptionOnError(#root)" />
</int:chain>
// Note: I want to replace the above int:chain with the below. Only the below section appears in my final configuration file deployed. The above int:chain is only as an example for Q&A.
<!-- NOT WORKING: Using Groovy script -->
<int:chain id="businessLayerResponse" input-channel="requestChannel" output-channel="responseChannel">
<int-xml:xslt-transformer xsl-templates="BookingClassFilter_Template" result-transformer="resultToDOMSource" />
<int-groovy:script>
def valBool = errorDetectionUtil.hasErrors(payload)
if(valBool) throw new AppException(#root)
return #root
</int-groovy:script>
</int:chain>
</beans>
下面是我的Javaclass:
import javax.xml.transform.dom.DOMSource;
@Component("errorDetectionUtil")
public class ErrorDetectionUtil {
public boolean hasErrors(DOMSource domSource) {
double countDbl = (double) errorsCounter.evaluate(domSource.getNode(), XPathConstants.NUMBER);
return ((int) countDbl > 0)
}
public Message<?> checkAndThrowExceptionOnError(Message<?> message) throws AppException {
if (hasErrors((DOMSource) message.getPayload())) {
throw new AppException(message);
}
return message;
}
}
// AppException extends org.springframework.integration.MessagingException
我不确定我做错了什么。下面是我在启动应用程序服务器时看到的异常堆栈跟踪。
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.integration.handler.MessageHandlerChain#13': Cannot create inner bean 'businessLayerResponse$child#2.handler' of type [org.springframework.integration.groovy.GroovyScriptExecutingMessageProcessor] while setting bean property 'handlers' with key [2]; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'businessLayerResponse$child#2.handler': Error setting property values; nested exception is org.springframework.beans.NotWritablePropertyException: Invalid property 'componentName' of bean class [org.springframework.integration.groovy.GroovyScriptExecutingMessageProcessor]: Bean property 'componentName' is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter?
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveInnerBean(BeanDefinitionValueResolver.java:282)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:121)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveManagedList(BeanDefinitionValueResolver.java:353)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:154)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1387)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1128)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:458)
at org.springframework.beans.factory.support.AbstractBeanFactory.getObject(AbstractBeanFactory.java:295)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:626)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479)
at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:389)
at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:294)
at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:112)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4729)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5167)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:725)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:701)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:717)
at org.apache.catalina.startup.HostConfig.deployDescriptor(HostConfig.java:586)
at org.apache.catalina.startup.HostConfig$DeployDescriptor.run(HostConfig.java:1750)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
at java.util.concurrent.FutureTask.run(FutureTask.java:262)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'businessLayerResponse$child#2.handler': Error setting property values; nested exception is org.springframework.beans.NotWritablePropertyException: Invalid property 'componentName' of bean class [org.springframework.integration.groovy.GroovyScriptExecutingMessageProcessor]: Bean property 'componentName' is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter?
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1423)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1128)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:458)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveInnerBean(BeanDefinitionValueResolver.java:271)
... 30 more
Caused by: org.springframework.beans.NotWritablePropertyException: Invalid property 'componentName' of bean class [org.springframework.integration.groovy.GroovyScriptExecutingMessageProcessor]: Bean property 'componentName' is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter?
at org.springframework.beans.BeanWrapperImpl.setPropertyValue(BeanWrapperImpl.java:1042)
at org.springframework.beans.BeanWrapperImpl.setPropertyValue(BeanWrapperImpl.java:902)
at org.springframework.beans.AbstractPropertyAccessor.setPropertyValues(AbstractPropertyAccessor.java:75)
at org.springframework.beans.AbstractPropertyAccessor.setPropertyValues(AbstractPropertyAccessor.java:57)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1420)
... 34 more
<groovy:script>
本身不是组件。它只能反映其他EIP特定组件的行为。
那么,您的 <service-activator>
也会在那里。但是您使用 <script>
.
expression
#root
变量是 SpEL 的一部分,正好是Message<?>
。对于脚本,它被拆分为payload
和headers
变量。是的,你应该在没有#
的情况下使用它们。
正确的,您的 errorDetectionUtil
在 Groovy 脚本中可用,因为 Spring 集成 3.0。
对我的 spring 集成进行以下更改解决了问题:
<int:chain id="businessLayerResponse" input-channel="requestChannel" output-channel="responseChannel">
<int-xml:xslt-transformer xsl-templates="BookingClassFilter_Template" result-transformer="resultToDOMSource" />
<int:service-activator>
<int-groovy:script>
def valBool = errorDetectionUtil.hasErrors(payload)
def message = org.springframework.integration.support.MessageBuilder.withPayload(payload).copyHeaders(headers).build()
if(java.lang.Boolean.valueOf(valBool)) {
throw new x.y.z.AppException(message)
}
return message
</int-groovy:script>
</int:service-activator>
</int:chain>
注意:脚本中需要完全限定 java class 个名称。