Я долгое время использовал удаленное удаленное взаимодействие, но насколько я помню, я нашел решение этой проблемы с помощью создания подкласса 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();
}
}
}
CustomRemoteExecutor:
@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));
}
Надеюсь, это поможет.