一、问题描述
今天服务升级了一个版本,在发送rabbitmq消息时报错NPE
java.lang.NullPointerException: Cannot invoke “org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry$FunctionInvocationWrapper.setSkipOutputConversion(boolean)” because “functionToInvoke” is null
at org.springframework.cloud.stream.function.StreamBridge.getStreamBridgeFunction(StreamBridge.java:215)
at org.springframework.cloud.stream.function.StreamBridge.send(StreamBridge.java:170)
二、问题排查
根据报错,可以知道是 functionToInvoke
为空,看 StreamBridge
源码(项目用的是Spring Cloud Stream)
跟进 functionCatalog.lookup
方法,一直往下,来到 BeanFactoryAwareFunctionRegistry
的 lookup
方法
发现是满足 !isFunctionDefinitionEligible(functionDefinition)
条件返回的 null,那就说明 isFunctionDefinitionEligible
方法返回了 false,debug 进去看
发现 definition
竟然包含了一个空字符串,然后开始寻找 this.functionProperties.getIneligibleDefinitions()
的由来,很显然这个是在项目启动的时候塞值的,于是在 FunctionProperties
类的 setIneligibleDefinitions
方法上打上断点,重启项目
发现确实塞了个空字符串,于是顺着往上找
发现是 kafka
相关的东西,sendToDlqAndContinue
是 kafka
的东西,但是为什么后面拼了一个逗号,不能理解,于是又找在哪里添加这个逗号的,然后在 KafkaStreamsBinderEnvironmentPostProcessor
里找到了代码
所以这个空字符串,是在 environment.getProperty(ineligibleDefinitionsPropertyKey)
里获取的,于是在 MutablePropertySources
类的所有添加方法上打上断点重来
最后在 addLast
方法里找到了,发现是微软云的 AzurePasswordlessEnvironmentPostProcessor
类中设置的
然后这段代码看着就很迷惑,创建一个空列表,然后用 String.join
,这么干的意义是什么???
然后就去github看,发现这个问题在3周前修复了
呃……这个文件直接被删了
三、解决问题
由于微软云解决问题的版本还是beta版本,暂时没考虑升级来解决问题
在配置文件里加上如下配置来解决
spring:
cloud:
function:
ineligible-definitions: xxxxx
xxxxx可以是任意字符串