如何在 spring 远程处理中设置动态 header

how to set dynamic header in spring remoting

我们需要使用 spring 远程调用 Bean class,并在调用中设置动态 header。我们可以在 HttpInvokerProxyFactoryBean 中设置自定义 HttpInvokerRequestExecutor 并添加 header 但是如何设置为请求即时生成的动态 header?

In the Config class, declaring the HttpInvokerProxyFactoryBean
@Bean
@Qualifier("service")
public HttpInvokerProxyFactoryBean invoker() {
    HttpInvokerProxyFactoryBean invoker = new HttpInvokerProxyFactoryBean();
    invoker.setServiceUrl(url);
    invoker.setServiceInterface(Service.class);
    return invoker;
}

In the invoker class
@Autowired
Service service;

public void invoke(Bean bean) {
    service.process(bean);
}

我使用 spring 远程处理已经有很长时间了,但据我所知,我通过子类化 SimpleHttpInvokerRequestExecutor 找到了解决此问题的方法,当您未将任何自定义请求执行程序设置为 HttpInvokerProxyFactoryBean 时,这是默认设置。

恕我直言,您可以编写一个可以设置自定义 header 值的自定义请求执行器和一个简单的辅助组件,该组件在下一个请求之前将动态提供的值设置为执行器。

CustomHttpInvokerRequestExecutor:

public class CustomHttpInvokerRequestExecutor extends SimpleHttpInvokerRequestExecutor {

private Map<String, String> headers;

public void setHeaders(Map<String, String> headers) {
    this.headers = headers;
}

@Override
protected void prepareConnection(HttpURLConnection connection, int contentLength) throws IOException {
    super.prepareConnection(connection, contentLength);

    if (headers != null) {
        // adding our custom headers
        for (String headerName : headers.keySet()) {
            connection.setRequestProperty(headerName, headers.get(headerName));
        }
        // do not want to persist headers for another request!
        headers.clear();
    }
}
}

自定义远程执行器:

@Component
public class CustomRemoteExecutor {

@Autowired
private HttpInvokerProxyFactoryBean factoryBean;

/*
 * May be you should need a synchronized modifier here if there is possibility
 * of multiple threads access here at the same time
 */
public void executeInTemplate(Map<String, String> headers, Runnable task) {
    CustomHttpInvokerRequestExecutor executor = (CustomHttpInvokerRequestExecutor) factoryBean.getHttpInvokerRequestExecutor();
    executor.setHeaders(headers);
    task.run();
}

}

然后你就可以通过下面的方式使用它了:

@Bean
@Qualifier("service")
public HttpInvokerProxyFactoryBean invoker() {
    HttpInvokerProxyFactoryBean invoker = new HttpInvokerProxyFactoryBean();
    invoker.setServiceUrl(testUrl);
    invoker.setServiceInterface(Service.class);
    // set our custom request executor
    CustomHttpInvokerRequestExecutor executor = new CustomHttpInvokerRequestExecutor();
    invoker.setHttpInvokerRequestExecutor(executor);

    return invoker;
}

@Autowired
CustomRemoteExecutor executor;

@Autowired
Service service;

public void invoke(Bean bean) {

    // when you need custom headers
    Map<String, String> headers = new HashMap<>();
    headers.put("CUSTOM_HEADER", "CUSTOM_VALUE");
    headers.put("CUSTOM_HEADER2", "CUSTOM_VALUE2");
    executor.executeInTemplate(headers, () -> service.process(bean));

}

这里有一个缺点,正如我在评论中所述,如果您在多线程环境中执行代理服务客户端(可能是服务器到服务器的请求),您应该考虑使用 executeInTemplate 方法 synchronized

如果您的服务方法需要 return 一些 object,那么您可以向 CustomRemoteExecutor 添加另一个辅助方法,并在需要时使用它 return 东西。这里的方法可以有相同的名字,所以它可以重载前一个我认为更好的方法。

public <T> T executeInTemplate(Map<String, String> headers, Callable<T> task) {
    CustomHttpInvokerRequestExecutor executor = (CustomHttpInvokerRequestExecutor) factoryBean.getHttpInvokerRequestExecutor();
    executor.setHeaders(headers);

    try {
        return task.call();
    } catch (Exception e) {
        // it is better to log this exception by your preferred logger (log4j, logback
        // etc.)
        e.printStackTrace();
    }

    return null;
}

您还可以像下面这样使用:

@Autowired
CustomRemoteExecutor executor;

@Autowired
ISampleService service;

public void invoke(Bean bean) {

    // when you need custom headers
    Map<String, String> headers = new HashMap<>();
    headers.put("CUSTOM_HEADER", "CUSTOM_VALUE");
    headers.put("CUSTOM_HEADER2", "CUSTOM_VALUE2");

    // assume that service.returnSomething() method returns String
    String value = executor.executeInTemplate(headers, () -> service.returnSomething(bean));

}

希望对您有所帮助。