2

我通过扩展创建了一个自定义 Web 服务客户端,WebServiceGatewaySupport还实现了自定义ClientInterceptor以记录一些请求/响应数据。我必须为每个调用创建新的拦截器,因为它必须存储一些关于请求的数据。

当我给我的客户打两个或多个电话时,就会出现问题。第一个请求应用它自己的拦截器和它的clientId. 第二个也应该这样做。但是由于两个请求WebServicetemplate在我的客户端中使用相同,第二个请求用它自己的拦截器替换了拦截器clientId

结果,我应该得到以下输出到控制台:

Request: clientId-1
Request: clientId-2
Response: clientId-1
Response: clientId-2

但我得到了这个:

Request: clientId-1
Request: clientId-2
Response: clientId-2
Response: clientId-2

这里是代码示例(只是为了理解它应该如何工作):

@Data
class Response {
    private final String result;

    public Response(String result) {
        this.result = result;
    }
}

@Data
class Request {
    private final String firstName;
    private final String lastName;
}

@Data
class Context {
    private final String clientId;
}

@Data
class Client {
    private final String clientId;
    private final String firstName;
    private final String lastName;
}

class CustomInterceptor extends ClientInterceptorAdapter {
    private final String clientId;

    public CustomInterceptor(String clientId) {
        this.clientId = clientId;
    }

    @Override
    public boolean handleRequest(MessageContext messageContext) throws WebServiceClientException {
        System.out.println("Request: " + clientId);
        return true;
    }

    @Override
    public boolean handleResponse(MessageContext messageContext) throws WebServiceClientException {
        System.out.println("Response: " + clientId);
        return true;
    }

    @Override
    public boolean handleFault(MessageContext messageContext) throws WebServiceClientException {
        System.out.println("Error: " + clientId);
        return true;
    }
}

@Component
class CustomClient extends WebServiceGatewaySupport {

    public Response sendRequest(Request request, Context context) {
        CustomInterceptor[] interceptors = {new CustomInterceptor(context.getClientId())};
        setInterceptors(interceptors);
        return (Response) getWebServiceTemplate().marshalSendAndReceive(request);
    }
}

@Service
@RequiredArgsConstructor
class CustomService {

    private final CustomClient customClient;

    public String call(Request request, Context context) {
        Response response = customClient.sendRequest(request, context);
        return response.getResult();
    }
}

@RestController
@RequestMapping("/test")
@RequiredArgsConstructor
class CustomController {

    private final CustomService service;

    public CustomController(CustomService service) {
        this.service = service;
    }

    @PostMapping
    public String test(@RequestBody Client client) {
        Request request = new Request(client.getFirstName(), client.getLastName());
        Context context = new Context(client.getClientId());
        return service.call(request, context);
    }
}

是否可以为每个调用实现具有某种状态的自定义拦截器?最好没有任何锁定WebServicetemplate以避免性能下降。

4

1 回答 1

0

好的。我找到了适合我的情况的解决方案。我创建了一个实现WebServiceMessageCallback并使用它,我将每个请求的数据保存在拦截器中,而不是在WebServiceMessagemime 标头中。

@Data
class CustomMessageCallback implements WebServiceMessageCallback {

    private final String clientId;
    
    @Override
    public void doWithMessage(WebServiceMessage message) throws IOException, TransformerException {
        MimeHeaders headers = ((SaajSoapMessage) message).getSaajMessage().getMimeHeaders();
        headers.addHeader("X-Client-Id", clientId);
    }
}

并在我的客户端实现中传递这个回调:

@Component
class CustomClient extends WebServiceGatewaySupport {

    public Response sendRequest(Request request, Context context) {
        CustomInterceptor[] interceptors = {new CustomInterceptor()};
        setInterceptors(interceptors);
        return (Response) getWebServiceTemplate()
            .marshalSendAndReceive(request, new CustomMessageCallback(context.getClientId()));
    }
}

所以现在我可以在通过拦截器处理请求/响应/错误时获取这些数据。

@Override
public boolean handleRequest(MessageContext messageContext) throws WebServiceClientException {
    String clientId = ((SaajSoapMessage) messageContext.getRequest())
        .getSaajMessage()
        .getMimeHeaders()
        .getHeader("X-Client-Id")[0];
    System.out.println("Request: " + clientId);
    return true;
}
于 2020-10-21T22:27:53.193 回答