因为rocketmq-spring-boot在初始化时会用DefaultRocketMQListenerContainer.getMessageType方法通过反射获取RocketMQListener接口以获取泛型参数(就是onMessage的入参类型)。getMessageType这个方法在rocketmq-spring-boot:2.0.3存在bug。如果@RocketMQMessageListener所在类和其父类均没有implements实现接口,就会陷入死循环导致无法步骤。如果继承了接口,但是不包含RocketMQListener接口,则会导致参数类型解析错误。如图
private Class getMessageType() {
Class<?> targetClass = AopProxyUtils.ultimateTargetClass(rocketMQListener);
Type[] interfaces = targetClass.getGenericInterfaces();
Class<?> superclass = targetClass.getSuperclass();
while ((Objects.isNull(interfaces) || 0 == interfaces.length) && Objects.nonNull(superclass)) {
interfaces = superclass.getGenericInterfaces();
superclass = targetClass.getSuperclass();
}
if (Objects.nonNull(interfaces)) {
for (Type type : interfaces) {
if (type instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) type;
if (Objects.equals(parameterizedType.getRawType(), RocketMQListener.class)) {
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
if (Objects.nonNull(actualTypeArguments) && actualTypeArguments.length > 0) {
return (Class) actualTypeArguments[0];
} else {
return Object.class;
}
}
}
}
return Object.class;
} else {
return Object.class;
}
}
这个问题在github[ISSUE #151]被提出,2019-12-19被修复。
private Type getMessageType() {
Class<?> targetClass;
if (rocketMQListener != null) {
targetClass = AopProxyUtils.ultimateTargetClass(rocketMQListener);
} else {
targetClass = AopProxyUtils.ultimateTargetClass(rocketMQReplyListener);
}
Type matchedGenericInterface = null;
while (Objects.nonNull(targetClass)) {
Type[] interfaces = targetClass.getGenericInterfaces();
if (Objects.nonNull(interfaces)) {
for (Type type : interfaces) {
if (type instanceof ParameterizedType &&
(Objects.equals(((ParameterizedType) type).getRawType(), RocketMQListener.class) || Objects.equals(((ParameterizedType) type).getRawType(), RocketMQReplyListener.class))) {
matchedGenericInterface = type;
break;
}
}
}
targetClass = targetClass.getSuperclass();
}
if (Objects.isNull(matchedGenericInterface)) {
return Object.class;
}
Type[] actualTypeArguments = ((ParameterizedType) matchedGenericInterface).getActualTypeArguments();
if (Objects.nonNull(actualTypeArguments) && actualTypeArguments.length > 0) {
return actualTypeArguments[0];
}
return Object.class;
}
因此如果使用的rocketmq-spring-boot:2.0.3使用的时间要注意。RocketMQListener接口一定要定义在@RocketMQMessageListener所在类或者其超类。否则会导致死循环或者参数类型解析错误。当然更好的方法是做组件升级。