I was looking at a post from 2014 about using Spring AOP for logging HTTP requests/replies:
Spring integration + logging response time for http adapters(or any endpoint)
To this end, I tried this AOP configuration:
<aop:config >
<aop:aspect id="myAspect" ref="inboundOutboundHttpLogging">
<aop:pointcut id="handleRequestMessageMethod"
expression="execution(* org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleRequestMessage(*))
and
args(message))" />
<aop:before method="requestMessageSent" pointcut-ref="handleRequestMessageMethod" arg-names="message"/>
</aop:aspect>
</aop:config>
Is there perhaps a newer way of using AOP for logging HTTP requests? I want to avoid having to put per-request logging (ie outbound-gateway advice on each gateway).
Thanks for any pointers.
The handleRequestMessage()
is essentially an input message to this gateway and output. So, if you don't like implementing an AbstractRequestHandlerAdvice
and adding it into each your gateway via their <request-handler-advice-chain>
, then consider to use a <wire-tap>
for input and output channels of those gateway.
You may implement, though, a BeanPostProcessor.postProcessBeforeInitialization()
to add your custom AbstractRequestHandlerAdvice
into those HTTP gateways you are interested in.
My point is that <aop:aspect>
you are presenting us really might lead to some unexpected behavior, like that final
method concern you have edit out from your question...
Based upon the suggestions made by @artem-bilan, I was able to find a solution similar to AOP for injecting logging AbstractRequestHandlerAdvice
into HTTP outbound request processing. I'm contributing this as a way of showing a possible solution for anyone else who comes across this question.
As @artem-bilan mentions, there is a mechanism for injecting AbstractRequestHandlerAdvice
into a AbstractReplyProducingMessageHandler
such as an HttpRequestExecutingMessageHandler
. In my case, I'm wanting to log the message contents (header and payload) prior to the HTTP call and also log the return message (header and payload). This works nicely.
@artem-bilan suggests that the BeanPostProcessor
mechanism can allow to inject the advice without having to add that declaration to each http outbound bean. The BeanPostProcessor
looks like this:
public class AddHttpOutboundAdvicePostProcessor implements BeanPostProcessor {
final List<Advice> adviceList;
final AddHttpOutboundAdvicePostProcessor(List<Advice> adviceList) {
this.adviceList = adviceList;
}
@Override
public Object postProcessAfterInitialization(@NonNull Object bean,
@NonNull String beanName)
throws BeansException {
if (bean instanceof AbstractHttpRequestExecutingMessageHandler) {
((AbstractHttpRequestExecutingMessageHandler) bean).setAdviceChain(adviceList);
}
return bean;
}
}
We need to set up this bean into our context. (I'm a die-hard declarative fan hence this is in XML.)
<bean id = "addHttpLoggingPostProcessor"
class = "com.my.package.AddHttpOutboundAdvicePostProcessor" >
<constructor-arg name="adviceList>
<util:list>
<ref bean="outboundLogger" />
</util:list>
</constructor-arg>
</bean>
Here, the outboundLogger
is a bean that managers the request-handler-advice
. In my choice of implementation, I'm sending a copy of the outbound message to a channel for logging beforehand, and a copy of the response message down another channel for logging the response. The XML declaration of the bean takes the two channel names as constructors:
<bean id="outboundLogger" class="com.my.package.HttpRequestProcessorLogger" >
<constructor-arg name="requestLoggingChannelName" value="XXX" />
<constructor-arg name="responseLoggingChannelName" value="YYY" />
</bean>
where XXX
and YYY
are the names of channels to the components that perform the logging. I've set these channels to be ExecutorChannel
s so that the logging is performed asynchronously.
The HttpRequestProcessorLogger
bean manages the call to handleRequestMessage()
:
public class HttpRequestProcessorLogger extends AbstractRequestHandlerAdvice {
private MessageChannel requestLoggingChannel;
private MessageChannel responseLoggingChannel;
private String requestLoggingChannelName;
private String responseLoggingChannelName;
private BeanFactory beanFactory;
public HttpRequestProcessorLogger(String requestLoggingChannelName, String responseLoggingChannelName) {
this.requestLoggingChannelName = requestLoggingChannelName;
this.responseLoggingChannelName = responseLoggingChannelName;
}
@Override
protected Object doInvoke(ExecutionCallback callback, Object target, Message<?> message) {
getChannels();
requestLoggingChannel.send(message);
final Object result = callback.execute();
final message<?> outputMessage =
(MessageBuilder.class.isInstance(result) ? ((MessageBuilder<?>) result).build()
: (Message<?>) result;
responseLoggingChannel.send(outputMessage);
return outputMessage;
}
private synchronized void getChannels() {
if (requestLoggingChannelName != null) {
final DestinationResolver<MessageChannel>
channelResolver = ChannelResolverUtils.getChannelResolver(this.beanFactory);
requestLoggingChannel = channelResolver.resolverDestination(requestLoggingChannelName);
responseLoggingChannel = channelResolver.resolverDestination(responseLoggingChannelName);
requestLoggingChannelName = null;
responseLoggingChannelName = null;
}
}
@Override
public void setBeanFactory(@NonNull BeanFactory beanFactory) throws BeanException {
this.beanFactory = beanFactory;
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.