SpringCloudBus自定义事件踩坑

编程

本文基于Spring Cloud Greenwich.SR3,Spring Boot 2.1.10.RELEASE

偶然发现Spring Cloud还有这个组件,通过结合消息中间件(RabbitMQ或者Kafka),使得发布的Spring事件可以传递给其他JVM项目,感觉很不错,就写了个demo试了一下,代码可以参考这里(PS:这个代码是填坑之后的)。

结果无论怎么试,RabbitMQ的控制台都观察不到消息传递,说明项目那边没有发出任何消息。

更坑爹的是,如果你在Google上搜索Bus的教程,全部都是Spring Cloud Config相关,没一点有用的......

最后我在BusAutoConfiguration中发现了这么一段代码

@EventListener(classes = RemoteApplicationEvent.class)

public void acceptLocal(RemoteApplicationEvent event) {

if (this.serviceMatcher.isFromSelf(event)

&& !(event instanceof AckRemoteApplicationEvent)) {

this.cloudBusOutboundChannel.send(MessageBuilder.withPayload(event).build());

}

}

看来Spring在将事件发布到MQ之前,会有一个判断

public boolean isFromSelf(RemoteApplicationEvent event) {

String originService = event.getOriginService();

String serviceId = getServiceId();

return this.matcher.match(originService, serviceId);

}

public String getServiceId() {

return this.id;

}

然后经过调试发现,这里的originService=producer-1,serviceId=producer-8111-随机字符串,很明显是不相等的。

这里id的赋值是通过构造方法进行的,整个工程构造方法调用的唯一一个地方就在BusAutoConfiguration这个配置里

@Bean

public ServiceMatcher serviceMatcher(@BusPathMatcher PathMatcher pathMatcher,

BusProperties properties, Environment environment) {

String[] configNames = environment.getProperty(CLOUD_CONFIG_NAME_PROPERTY,

String[].class, new String[] {});

ServiceMatcher serviceMatcher = new ServiceMatcher(pathMatcher,

properties.getId(), configNames);

return serviceMatcher;

}

很显然这里读取的是BusProperties这个配置文件,然而你会发现,这里的id无论你配成什么,他都会给你改成上边那种形式,罪魁祸首如下所示....

//BusEnvironmentPostProcessor.java

@Override

public void postProcessEnvironment(ConfigurableEnvironment environment,

SpringApplication application) {

Map<String, Object> map = new HashMap<String, Object>();

map.put("spring.cloud.bus.id", getDefaultServiceId(environment));

addOrReplace(environment.getPropertySources(), map);

}

private String getDefaultServiceId(ConfigurableEnvironment environment) {

return "${vcap.application.name:${spring.application.name:application}}:${vcap.application.instance_index:${spring.application.index:${local.server.port:${server.port:0}}}}:${vcap.application.instance_id:${random.value}}";

}

Spring使用自定义的ID生成替换掉了那个配置!

原因找到了之后,解决很简单,在发布事件的时候,使用BusProperties的ID,保证if判断为真即可

@RequestMapping("/hello")

@RestController

public class HelloController {

@Autowired

private ApplicationContext applicationContext;

@Autowired

private BusProperties busProperties;

@GetMapping("/test")

public String test(@RequestParam("message") String message) {

String id = busProperties.getId();

applicationContext.publishEvent(new CustomApplicationEvent(this, id, null, message));

return "发送成功!";

}

}

以上是 SpringCloudBus自定义事件踩坑 的全部内容, 来源链接: utcz.com/z/510830.html

回到顶部