业务场景
由于这是项目辅助服务,用于向其它各个服务推送数据
系统B通过kafka实时的接收来自系统A的消息,因为系统B只有一个实例,之前系统B发版都需要关闭系统A,这样极大的削减了系统的灵活性,给系统维护带来了极大的不便利;因为系统B只接受来自系统A的消息,因此我们可以手动控制是否接受消息,待系统B将逻辑处理完毕后,再进行发版。
解决方式
由于数据传输用的是使用kafka,系统B可以配置监听器的手动暂停与启动,来控制数据的接收。具体实现如下
@Configuration
@EnableKafka
public class ReceiverConfig{
@Value("kafka.bootstrap-servers")
private String bootstrapServers;
@Value("kafka.consumerser.group-id")
private String consumerGroup;
@Bean
public Map<String,Object> consumerConfigs(){
Map<String,Object> props = new HashMap<>();
props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG,bootstrapServers);
props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG,StringDeserializer.class);
props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG,StringDeserializer.class);
props.put(ConsumerConfig.GROUP_ID_CONFIG,consumerGroup);
return props;
}
@Bean
public KafkaListenerContainerFactory<ConcurrentMessageListrnerContainer<String,String> kafkaListenerContainerFactory(){
CurrentKafkaListenerContainerFactory<String,String> factory = new CurrentKafkaListenerContainerFactory<>();
factory.setConsumerFactory(new DefaultKafkaConsumerFactory<>(consumerConfigs()));
//并发数量
factory.setConcurrency(concurrency);
//开启批量监听
factory.setBatchListener(type);
// 被过滤的消息将被丢弃
factory.setAckDiscarded(true);
// 设置记录筛选策略
factory.setRecordFilterStrategy(new RecordFilterStrategy() {
@Override
public boolean filter(ConsumerRecord consumerRecord) {
String msg = consumerRecord.value().toString();
if(Integer.parseInt(msg.substring(msg.length() - 1)) % 2 == 0){
return false;
}
// 返回true消息将会被丢弃
return true;
}
});
// ack模式
factory.getContainerProperties()
.setAckMode(ContainerProperties.AckMode.MANUAL_IMMEDIATE);
// 禁止消费者监听器自启动
factory.setAutoStartup(false);
return factory;
}
@Bean
public Receiver receiver(){
return new Receiver();
}
}
监听器指定id
@KafkaListener(topics = {
"mytopics"},
groupId = "my-consumer-group",
containerFactory = "kafkaListenerContainerFactory",
id = "myListenerId")
public void test(List<String> message){
System.out.println("接收到的消息:" + message);
}
接口控制指定监听器id的启动与暂停
@RestController
@RequestMapping("/kfk")
public class KafkaExecuteController{
private static final String myListenerId = "myListenerId";
@Autowired
private KafkaListenerEndpointRegistry registry;
/** * 开启监听 */
@GetMapping("/start")
public String start() {
// 判断监听容器是否启动,未启动则将其启动
if (!registry.getListenerContainer(myListenerId).isRunning()) {
registry.getListenerContainer(myListenerId).start();
return "===> kafka Listener start"
}
// 恢复启动
registry.getListenerContainer(myListenerId).resume();
return "===> kafka Listener resume";
}
/** * 关闭监听 */
@GetMapping("/stop")
public String stop() {
// 暂停监听
registry.getListenerContainer(myListenerId).pause();
return "===> kafka Listener stop";
}
}