Spring Integration Header没有注入Service Activator POJO

时间:2017-04-20 04:21:48

标签: spring multithreading spring-integration

Spring Integration Header没有被注入到Service Activator POJO中。这只发生在负载测试时(小于10 tps)。 正常流量正如预期的那样工作。 Spring整合流程

Splitter -> executor channel -> service activator -> aggregator.

SI version 4.1.2.RELEASE
Spring Version 4.1.2.RELEASE
Java version 1.8.0_60

//service activator -Method     
public ProductDetail getProductDetails(final String productID,
            @Header(STATS) final Stats statsType,
            @Header(SKU) final String sku,
            @Header(PRODUCT_LIST) final Collection<String> productList,
            @Header(NO_OF_PRODUCTS) final String size) 

final MessageBuilder<Map<String, Object>> msgBuilder = MessageBuilder
                .withPayload(payload);//Map<String, Object> payload
this.addMessageHeaders(msgBuilder, httpHeadersMap, statsType);


private final boolean addMessageHeaders(MessageBuilder<?> msgBuilder,
            final Map<String, String> httpHeadersMap, final Stats statsType) {
        if ((httpHeadersMap != null) && (httpHeadersMap.size() > 0)) {
            for (Map.Entry<String, String> entry : httpHeadersMap.entrySet()) {
                msgBuilder.setHeader(entry.getKey(), entry.getValue());
            }
        }
        if (statsType != null) {
            msgBuilder.setHeader(STATS, statsType);
        }
        return true;
}
  

org.springframework.messaging.MessageHandlingException:嵌套异常是java.lang.IllegalArgumentException:必需的标头不可用:STATS       在org.springframework.integration.handler.MethodInvokingMessageProcessor.processMessage(MethodInvokingMessageProcessor.java:78)〜[spring-integration-core-4.1.2.RELEASE.jar:na]       在org.springframework.integration.handler.ServiceActivatingHandler.handleRequestMessage(ServiceActivatingHandler.java:71)〜[spring-integration-core-4.1.2.RELEASE.jar:na]       在org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleMessageInternal(AbstractReplyProducingMessageHandler.java:99)〜[spring-integration-core-4.1.2.RELEASE.jar:na]       在org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:78)〜[spring-integration-core-4.1.2.RELEASE.jar:na]       在org.springframework.integration.dispatcher.AbstractDispatcher.tryOptimizedDispatch(AbstractDispatcher.java:116)〜[spring-integration-core-4.1.2.RELEASE.jar:na]       在org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch(UnicastingDispatcher.java:101)〜[spring-integration-core-4.1.2.RELEASE.jar:na]       在org.springframework.integration.dispatcher.UnicastingDispatcher.access $ 000(UnicastingDispatcher.java:48)〜[spring-integration-core-4.1.2.RELEASE.jar:na]       在org.springframework.integration.dispatcher.UnicastingDispatcher $ 1.run(UnicastingDispatcher.java:92)〜[spring-integration-core-4.1.2.RELEASE.jar:na]       在org.springframework.integration.util.ErrorHandlingTaskExecutor $ 1.run(ErrorHandlingTaskExecutor.java:52)〜[spring-integration-core-4.1.2.RELEASE.jar:na]       在xx.run(DelegatingContextRunnable.java:40)〜[xx-core-3.xx.jar:3.24.0.52]       在java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)〜[na:1.8.0_60]       在java.util.concurrent.ThreadPoolExecutor $ Worker.run(ThreadPoolExecutor.java:617)〜[na:1.8.0_60]       在java.lang.Thread.run(Thread.java:745)〜[na:1.8.0_60]   引起:java.lang.IllegalArgumentException:必需的标头不可用:STATS       在org.springframework.util.Assert.isTrue(Assert.java:68)〜[spring-core-4.2.2.RELEASE.jar:4.2.2.RELEASE]       at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)〜[na:1.8.0_60]       at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)〜[na:1.8.0_60]       at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)〜[na:1.8.0_60]       在java.lang.reflect.Method.invoke(Method.java:497)〜[na:1.8.0_60]

<int:channel id="retrieve-product.in" />
<int:channel id="retrieve-product.out" />
<int:channel id="retrieve-product.err" />
<int:channel id="retrieve-product.splitter.in"/>
<int:channel id="retrieve-product.sa.in">
    <int:dispatcher task-executor="testExecutor" failover="false"/>
</int:channel>
<int:channel id="retrieve-product.aggregator.in"/>
<int:channel id="retrieve-product.transformer.in"/>

<bean id="retrieveProductsServiceActivatorSupport" class="com.test.eip.serviceactivator.support.RetrieveProductsServiceActivatorSupport" />
<bean id="retrieveProductsServiceActivator" class="com.test.eip.serviceactivator.RetrieveProductsServiceActivator" />
<bean id="retrieveProductsAggregator" class="com.test.eip.aggregator.RetrieveProductsAggregator" />
<bean id="retrieveProductResponseTransformer" class="com.test.eip.transformer.RetrieveProductsResponseTransformer" />
<bean id="productGroupsConfig" class="com.test.support.ProductGroupsConfig" >
    <constructor-arg index="0" value="ProductMapping.xml" />
</bean>
<bean id="payloadSizeBasedReleaseStrategy" class="com.test.eip.aggregator.support.PayloadSizeBasedReleaseStrategy" />
<oxm:jaxb2-marshaller id="productConfigJaxbMarshaller" context-path="com.test.product.config.types" />

<int:gateway id="retrieveProductsGateway" service-interface="com.test.eip.gateway.IProductGateway" error-channel ="retrieve-product.err">
    <int:method name="getProductsResponse" request-channel="retrieve-product.in" reply-channel="retrieve-product.out" />
</int:gateway>

<int:header-enricher input-channel="retrieve-product.in" output-channel="retrieve-product.splitter.in">
    <int:header name="API_NAME" value="retrieve-product" />
</int:header-enricher>
<!-- Input List<String> contain product numbers --> 
<int:splitter id="productListSplitter" input-channel="retrieve-product.splitter.in" 
                output-channel="retrieve-product.sa.in"></int:splitter>
<!-- Retrieve Product Features from USING API -->               
<int:service-activator input-channel="retrieve-product.sa.in"
    ref="retrieveProductsServiceActivator" method="getProductDetails"
    output-channel="retrieve-product.aggregator.in"
    id="retrieve-product-service-activator" />
<!-- Aggregate result from Parallel Call -->
<int:aggregator input-channel="retrieve-product.aggregator.in"
    output-channel="retrieve-product.transformer.in"
    method="aggregateProductDetails" ref="retrieveProductsAggregator"
    release-strategy="payloadSizeBasedReleaseStrategy"
    release-strategy-method="canRelease">
</int:aggregator>

<!-- Generate Service Response-->
<int:transformer id="retrieve-product-ResponseTransformer" method="transform"
        ref="retrieveProductResponseTransformer" input-channel="retrieve-product.transformer.in" output-channel="retrieve-product.out" />

<!-- 
    Listen for error and generate response
 -->
<int:service-activator input-channel="retrieve-product.err"
    ref="testErrorHandler" method="handleExceptions"
    output-channel="retrieve-product.out"
    id="retrieve-product-err-handler" />

public interface IProductGateway {
    public RetrieveProductsResponse getProductsResponse(Message<?> inputMessage);
}

//Service
@Service
public class ProductsService implements IProductsService {
    @Autowired
    private IProductGateway retrieveProductsGateway;

    @Override
    public RetrieveProductsResponse getProductsResponse(
            final RetrieveProductsRequest retrieveProductsRequest,
            final Map<String, String> httpHeadersMap, final Stats statsType) {
        final ProductsReqType products = retrieveProductsRequest.getProducts();
        //populate productList From products
        final Collection<String> productList = new HashSet<>();
        httpHeadersMap.put(SKU, retrieveProductsRequest.getSKU());
        httpHeadersMap.put(NO_OF_PRODUCTS,
                String.valueOf(productList.size()));
        final MessageBuilder<Collection<String>> msgBuilder = MessageBuilder
                .withPayload(productList)
                .setHeader(PRODUCT_LIST, new HashSet<>(productList));
        this.addMessageHeaders(msgBuilder, httpHeadersMap, statsType);
        final Message<Collection<String>> inMsg = msgBuilder.build();
        LOG.debug("retrieveProductsGateway:: {}", this.retrieveProductsGateway);
        final RetrieveProductsResponse retrieveProductsResponse = this.retrieveProductsGateway
                .getProductsResponse(inMsg);
        return retrieveProductsResponse;
    }
}

//Jersey Filter is creating Stats setting it to requestContext( javax.ws.rs.container.ContainerRequestFilter)
/* Request Filter Creating and setting statsType 
*/
@Override
public void filter(final ContainerRequestContext requestContext) throws IOException {
    LOG.debug("filter(requestContext)::Entry");
    final Stats statsType = STATS_OBJ_FACTORY.createStats();
    final MultivaluedMap<String, String> headers = requestContext.getHeaders();
    statsType.setBegin(DT_FACTORY.newXMLGregorianCalendar(new GregorianCalendar()));
    requestContext.setProperty(STATS, statsType);
    LOG.debug("filter(requestContext)::Exit");
}

//Resource Method taking statsType and passing to ProductsService
/*javax.ws.rs.core.Context*/
@POST
@Path("retrieve-product")
@Produces(MyMediaType.PD_XML_MEDIA_TYPE)
@Consumes(MyMediaType.PD_XML_MEDIA_TYPE)
public Response getProducts(RetrieveProductsRequest retrieveProductsRequest,
        @Context final ContainerRequestContext containerRequestContext,
        @Context final HttpHeaders headers) {
    LOG.debug("getProducts::Entry");
    final Stats statsType = (Stats) containerRequestContext
            .getProperty(STATS);
    final Map<String, String> httpHeadersMap = ResourceHelper
            .getHttpHeadersAsMap(headers);
    final RetrieveProductsResponse retrieveProductsResponse = this.productsService
            .getProductsResponse(retrieveProductsRequest, httpHeadersMap, statsType);
    LOG.debug("getProducts::Exit");
    return Response.ok(retrieveProductsResponse).build();
}

谢谢,

1 个答案:

答案 0 :(得分:0)

  

所需标头不可用:STATS

简单地说,无论创建消息的上游是什么,都不会填充标题;您需要显示所有配置(可能还有代码)。 DEBUG记录和跟踪消息通常有助于调试这些条件。

一个常见的错误是缺乏线程安全性 - 例如在你的分离器中。