目录
1、pom文件的引入
2、kafkaConfig
3、消息的生产者(KafkaSender)
4、消息的消费者(KafkaReceiver)
5、yml配置文件
6、使用(so easy)
项目中原版使用的是rocketmq,由于客户那边用的是kafka。先把中间件更换长kafka,步入正题:
org.springframework.kafka
spring-kafka
package com.wlsj.gxdc.config;
import org.springframework.boot.autoconfigure.kafka.ConcurrentKafkaListenerContainerFactoryConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory;
import org.springframework.kafka.core.ConsumerFactory;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.kafka.listener.DeadLetterPublishingRecoverer;
import org.springframework.kafka.listener.SeekToCurrentErrorHandler;
import org.springframework.util.backoff.FixedBackOff;
@Configuration
public class KafkaConfig {
@Bean
public ConcurrentKafkaListenerContainerFactory, ?> kafkaListenerContainerFactory(
ConcurrentKafkaListenerContainerFactoryConfigurer configurer,
ConsumerFactory
package com.wlsj.gxdc.kafka;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Component;
@Component
@Slf4j
public class KafkaSender {
@Autowired
private KafkaTemplate kafkaTemplate;
//异步发送消息方法
public void sendAsynchronize(String topic, String message) {
kafkaTemplate.send(topic, message);
}
//同步发送消息方法
public void sendSynchronize(String topic, String message) throws Exception {
kafkaTemplate.send(topic, message).get();
}
}
package com.wlsj.gxdc.kafka;
import com.alibaba.fastjson.JSONObject;
import com.wlsj.gxdc.entity.Bicycle;
import com.wlsj.gxdc.entity.BicyclePosition;
import com.wlsj.gxdc.service.IBicyclePositionService;
import com.wlsj.gxdc.service.IBicycleService;
import lombok.extern.slf4j.Slf4j;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.stereotype.Component;
import java.util.Optional;
@Slf4j
@Component
public class KafkaReceiver {
@Autowired
private IBicyclePositionService bicyclePositionService;
@Autowired
private IBicycleService bicycleService;
@KafkaListener(topics = {"${kafka.topic.bicycle_topic}"})
public void listen1(ConsumerRecord, ?> record) {
Optional> kafkaMessage = Optional.ofNullable(record.value());
if (kafkaMessage.isPresent()) {
Object message = kafkaMessage.get();
JSONObject jsonObject = JSONObject.parseObject(message.toString());
if (null != jsonObject) {
Bicycle bicycle = JSONObject.toJavaObject(jsonObject, Bicycle.class);
try {
bicycleService.save(bicycle);
} catch (Exception e) {
log.info(e.getMessage());
}
}
log.info("kafka车辆备案消息:{}", message);
log.info("----------------- record =" + record);
}
}
@KafkaListener(topics = {"${kafka.topic.bicycle_position_topic}"})
public void listen2(ConsumerRecord, ?> record) {
Optional> kafkaMessage = Optional.ofNullable(record.value());
if (kafkaMessage.isPresent()) {
Object message = kafkaMessage.get();
JSONObject jsonObject = JSONObject.parseObject(message.toString());
if (null != jsonObject) {
BicyclePosition bicyclePosition = JSONObject.toJavaObject(jsonObject, BicyclePosition.class);
log.info("=======================bicyclePosition =" + bicyclePosition);
try {
bicyclePositionService.save(bicyclePosition);
bicyclePositionService.updatePositionByBicycleId(bicyclePosition);
} catch (Exception e) {
log.info(e.getMessage());
}
}
log.info("kafka车辆位置消息:{}", message);
}
}
}
server:
undertow:
io-threads: 6
worker-threads: 48
buffer-size: 1024
buffers-per-region: 1024
direct-buffers: true
port: ${PORT:8080}
# tomcat:
# max-swallow-size: -1
servlet:
context-path: /${spring.application.name}
compression:
enabled: true
mime-types: application/javascript,application/json,application/xml,text/html,text/xml,text/plain,text/css,image/*
management:
endpoints:
web:
exposure:
include: metrics,httptrace
spring:
servlet:
multipart:
max-file-size: 10MB
max-request-size: 10MB
kafka:
bootstrap-servers: 172.16.251.70:6667,172.16.251.77:6667,172.16.251.46:6667,172.16.251.66:6667, 172.16.251.87:6667, 172.16.251.85:6667, 172.16.251.73:6667, 172.16.251.61:6667
producer:
# 发生错误后,消息重发的次数。
retries: 0
#当有多个消息需要被发送到同一个分区时,生产者会把它们放在同一个批次里。该参数指定了一个批次可以使用的内存大小,按照字节数计算。
batch-size: 16384
# 设置生产者内存缓冲区的大小。
buffer-memory: 33554432
# 键的序列化方式
key-serializer: org.apache.kafka.common.serialization.StringSerializer
# 值的序列化方式
value-serializer: org.apache.kafka.common.serialization.StringSerializer
# acks=0 : 生产者在成功写入消息之前不会等待任何来自服务器的响应。
# acks=1 : 只要集群的首领节点收到消息,生产者就会收到一个来自服务器成功响应。
# acks=all :只有当所有参与复制的节点全部收到消息时,生产者才会收到一个来自服务器的成功响应。
acks: 1
properties:
sasl.mechanism: PLAIN
security.protocol: SASL_PLAINTEXT
sasl.jaas.config: org.apache.kafka.common.security.scram.ScramLoginModule required username="share_bikes" password="9cfb8e5b";
consumer:
# 自动提交的时间间隔 在spring boot 2.X 版本中这里采用的是值的类型为Duration 需要符合特定的格式,如1S,1M,2H,5D
auto-commit-interval: 1S
# 该属性指定了消费者在读取一个没有偏移量的分区或者偏移量无效的情况下该作何处理:
# latest(默认值)在偏移量无效的情况下,消费者将从最新的记录开始读取数据(在消费者启动之后生成的记录)
# earliest :在偏移量无效的情况下,消费者将从起始位置读取分区的记录
auto-offset-reset: earliest
# 是否自动提交偏移量,默认值是true,为了避免出现重复数据和数据丢失,可以把它设置为false,然后手动提交偏移量
enable-auto-commit: false
group-id: ${spring.profiles.active}-group
# 键的反序列化方式
key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
# 值的反序列化方式
value-deserializer: org.apache.kafka.common.serialization.StringDeserializer
properties:
sasl.mechanism: PLAIN
security.protocol: SASL_PLAINTEXT
sasl.jaas.config: org.apache.kafka.common.security.scram.ScramLoginModule required username="share_bikes" password="9cfb8e5b";
listener:
# 在侦听器容器中运行的线程数。
concurrency: 5
#listner负责ack,每调用一次,就立即commit
ack-mode: manual_immediate
missing-topics-fatal: false
kafka:
topic:
bicycle_topic: bikes_record
bicycle_position_topic: share_bikes
@Autowired
KafkaSender kafkaSender;
kafkaSender.sendAsynchronize(kafkaTopicPo.getBicyclePositionTopic(), JSON.toJSONString(bicyclePosition));