我使用 spring 远程处理已经很长时间了,但据我所知,我通过子类化 SimpleHttpInvokerRequestExecutor 找到了解决方案,当您没有将任何自定义请求执行器设置为 HttpInvokerProxyFactoryBean 时,这是默认设置。
恕我直言,您可以编写一个自定义请求执行器,您可以设置自定义标头值和一个简单的帮助器组件,该组件在下一个请求之前将动态提供的值设置给执行器。
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
如果您的服务方法需要返回某个对象,那么您可以添加另一个帮助方法CustomRemoteExecutor
并在需要返回某些内容时使用它,这是对我的回答的补充。该方法可以在这里具有相同的名称,因此它可以重载前一个,我认为这要好得多。
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));
}
希望能帮助到你。