我们需要使用Spring Remoting调用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);
}
答案 0 :(得分:0)
使用弹簧远程处理已经有很长时间了,但是据我所知,我通过子类化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));
}
希望有帮助。