как установить динамический заголовок в весеннем удаленном доступе - PullRequest
0 голосов
/ 08 января 2019

Нам нужно вызвать класс Bean с использованием пружинного удаленного взаимодействия, а также установить динамический заголовок в вызове. Мы можем установить пользовательский HttpInvokerRequestExecutor в HttpInvokerProxyFactoryBean и добавить заголовок, но как установить динамический заголовок, сгенерированный на лету для запроса?

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);
}

1 Ответ

0 голосов
/ 09 января 2019

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

}

Надеюсь, это поможет.

...