我有一个Spring Cloud Streams应用程序,其中的流侦听器使用来自输入通道的事件。一切运行顺利,直到我添加了AOP建议以记录处理方法的执行情况(在应用程序中的其他应用程序之间)。之后,测试开始失败并显示以下错误:
org.springframework.messaging.MessagingException:调用com.acme.fx.exchangerate.store.infrastructure.entrypoint.messaging.ExchangeRateStoreStreamListener $$ EnhancerBySpringCGLIB $$ 9795881e#handle [1 args];时引发的异常嵌套异常是java.lang.IllegalStateException:映射的处理程序方法类'com.acme.fx.exchangerate.store.infrastructure.entrypoint.messaging.ExchangeRateStoreStreamListener $$ EnhancerBySpringCGLIB $$ 9795881e $ MockitoMock $ 1733324661'并不是实际终结点的实例bean类'com.acme.fx.exchangerate.store.infrastructure.entrypoint.messaging.ExchangeRateStoreStreamListener $$ EnhancerBySpringCGLIB $$ 9795881e $$ EnhancerBySpringCGLIB $$ 2a2d55ce'。如果端点需要代理(例如,由于@Transactional),请使用基于类的代理。 HandlerMethod详细信息: ...
接收器定义:
应用程序代码如下:
public interface ExchangeRateStoreStreamSink {
String NEWEXCHANGERATE="new-exchange-rate";
@Input(NEWEXCHANGERATE)
SubscribableChannel newExchangeRate();
}
带有注释方法的流侦听器:
@EnableBinding(ExchangeRateStoreStreamSink.class)
public class ExchangeRateStoreStreamListener {
private CommandBus commandBus;
@Autowired
public ExchangeRateStoreStreamListener(CommandBus commandBus) {
this.commandBus = commandBus;
}
@Loggable(operationName="ExchangeRateConsumption")
@StreamListener(ExchangeRateStoreStreamSink.NEWEXCHANGERATE)
public void handle(NewExchangeRateMessage newExchangeRateMessage) {
AddExchangeRateCommand addExchangeRateCommand = new AddExchangeRateCommand(newExchangeRateMessage.from,
newExchangeRateMessage.to, newExchangeRateMessage.amount, newExchangeRateMessage.date);
commandBus.dispatch(addExchangeRateCommand);
}
}
测试:
@ExtendWith(SpringExtension.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
public class ExchangeRateStoreStreamListenerTest {
@Autowired
private ExchangeRateStoreStreamSink streamSink;
@SpyBean
private ExchangeRateStoreStreamListener streamListener;
@Test
public void test() {
SubscribableChannel input = streamSink.newExchangeRate();
NewExchangeRateMessage exchangeRateMessage = NewExchangeRateMessageFactory.aNewExchangeRateMessage();
input.send(new GenericMessage<>(exchangeRateMessage));
verify(streamListener).handle(any(NewExchangeRateMessage.class));
}
}
AOP方面:
@Aspect
@Component
public class LoggingAspect {
private static final String API_DOMAIN = "fx";
@Pointcut(value = "@annotation(loggable) && execution(* *(..))", argNames = "loggable")
public void loggableMethod(Loggable loggable) { }
@Around(value = "loggableMethod(loggable)", argNames = "pjp,loggable")
public Object logAccess(ProceedingJoinPoint pjp, Loggable loggable) throws Throwable {
final Signature signature = pjp.getSignature();
final Logger logger = LogManager.getLogger(signature.getDeclaringType());
logger.info( "api_domain={} _operation={} _message=\"Start operation\"",
API_DOMAIN, loggable.operationName());
try {
return pjp.proceed();
} catch (DomainError domainError) {
// Some logic here
}
}
}
任何帮助都非常欢迎。预先感谢!
答案 0 :(得分:3)
这是因为StreamListener已经是代理。有太多的要解释的地方,可能写博客是一个不错的话题。 。 。
无论如何,我很高兴,尽管您已经描述了您要解决的实际问题,可以通过一种更简单的方法来解决,这就是通过引入@Bean
@GlobalChannelInterceptor
public ChannelInterceptor channelInterceptor() {
return new ChannelInterceptor() {
@Override
public Message<?> preSend(Message<?> msg, MessageChannel mc) {
System.out.println("Before send to channel: " + mc);
return msg;
}
@Override
public void afterSendCompletion(Message<?> msg, MessageChannel mc, boolean bln, Exception excptn) {
System.out.println("After send completion to channel: " + mc);
}
@Override
public void postSend(Message<?> msg, MessageChannel mc, boolean bln) {
System.out.println("After send to channel: " + mc);
}
};
}
来实现的-实际上,该问题可以作为消息处理程序调用的环绕建议。
基本上是一个例子:
Before send to channel: input
Before send to channel: integrationFlowCreator.channel#0
===> SOME LOG MESSAGE INSIDE YOUR CODE
After send to channel: integrationFlowCreator.channel#0
After send completion to channel: integrationFlowCreator.channel#0
After send to channel: input
After send completion to channel: input
。 。 。这是它将产生的输出:
GlobalChannelInterceptor
您只需在配置中声明它,就可以了。它将应用于所有通道,因此您(使用逻辑)仅监视一次您想要的通道。
有关更多详细信息,请参考Javadoc中的command: mongod --port 27018
。
希望有帮助