Spring Boot 2.x 最佳实践之Spring for Apache Kafka集成

Spring Boot 2.x 最佳实践之Spring for Apache Kafka集成

原文:https://blog.csdn.net/hadues/article/details/88974967
这篇我们来讲解如何使用Spring Boot 2.x 和Spring Kafka 进行集成。

1. 关于Kafka 需要了解的

1.1 背景

Kafka 最初是由微软旗下LinkedIn(领英)公司采用Scale 语言开发开发的 分布式消息系统,后来捐献给了Apache基金会。

1.2 简介

Kafka 其实是一个分布式流处理平台,但是由于它拥有这样几个功能让它变得独特

1.消息流订阅和发布

流可以理解成字节流,TCP/IP Socket 通信传输数据包大多是字节流。 这个功能也就是说它拥有传统消息中间件的消息订阅和发布功能

2.消息流处理

3.分布式流存储

看到没?还拥有分布式存储的功能,所以它比传统的消息中间件要更加强大。

在这里插入图片描述

总结就是:

Kafka 是一个分布式流处理框架 可以像一个消息中间件一样读写数据流(即,发布和订阅消息) Kafka
还拥有分布式流处理以及存储到磁盘的功能,所以比消息中间件更加强大。
2.Spring Boot 2.x与Spring For Kafka 集成 Kafka 这么强大,Spring 官方当然也对其做了友好的支持,而且比原生的API开发更加简单、方便和快捷。

2.Spring Boot 2.x与Spring For Kafka 集成

Kafka 这么强大,Spring 官方当然也对其做了友好的支持,而且比原生的API开发更加简单、方便和快捷。

2.1 在Maven中添加POM依赖

添加web依赖,是因为我需要用@RestController 等注解测试接口 添加Kafka 流处理依赖和Spring 简化开发封装的依赖
添加自定义配置文件依赖是因为要自定义一些属性配置文件 添加Spring Boot 默认使用的最佳的日志框架 添加Spring和Kafka
的测试依赖

	    <!-- Web模块包括 Spring MVC 功能 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		
		<!-- Spring for Apache Kafka -->
		<dependency>
			<groupId>org.apache.kafka</groupId>
			<artifactId>kafka-streams</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.kafka</groupId>
			<artifactId>spring-kafka</artifactId>
		</dependency>

        <!-- 自定义配置文件需要 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-configuration-processor</artifactId>
			<optional>true</optional>
		</dependency>
		
		<!-- 使用SLF4J + Logback 作为日志框架 -->
	   <dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-logging</artifactId>
		</dependency>
		
		<!-- Spring for Apache Kafka Test -->
		<dependency>
			<groupId>org.springframework.kafka</groupId>
			<artifactId>spring-kafka-test</artifactId>
			<scope>test</scope>
		</dependency>
		
		<!-- Spring Test -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

2.2 激活配置文件application.properties

application.properties内容如下:

spring.profiles.active=dev

2.3 开发配置文件application-dev.properties

application-dev.properties

#内嵌容器配置
#配置应用程序的访问端口
server.port=8080

#配置应用程序的上下文
server.servlet.context-path=/

#配置Kafka集群IP地址,多个IP以逗号隔开
spring.kafka.bootstrap-servers=192.168.10.137:9092

#配置约定的订阅主题
com.xingyun.kafka.topic-name=topic.demo

#生产者客户端配置参数
#必要参数
spring.kafka.producer.key-serializer=org.apache.kafka.common.serialization.StringSerializer
spring.kafka.producer.value-serializer=org.apache.kafka.common.serialization.StringSerializer
#其他可选参数类型
#spring.kafka.producer.value-serializer=org.apache.kafka.common.serialization.ByteArraySerializer
#spring.kafka.producer.value-serializer=org.springframework.kafka.support.serializer.JsonSerializer
#可选参数
Kafka 生产者客户端Id,默认为"" 不设置为producer-1,producer-2
spring.kafka.producer.client-id=kafka.producer.client.id.demo
#重新尝试次数
spring.kafka.producer.retries=0

#消费者客户端配置参数
spring.kafka.consumer.key-deserializer=org.apache.kafka.common.serialization.StringDeserializer
spring.kafka.consumer.value-deserializer=org.apache.kafka.common.serialization.ByteArrayDeserializer
#设置消费者客户端Id
spring.kafka.consumer.client-id=kafka.client.id.1

#消费者群组ID,发布-订阅模式,即如果一个生产者,多个消费者都要消费,那么需要定义自己的群组,同一群组内的消费者只有一个能消费到消息
spring.kafka.consumer.group-id=kafka.consumer.group.id.1

#是否自动提交 关闭自动提交位移, 在消息被完整处理之后再手动提交位移.
spring.kafka.consumer.enable-auto-commit=true
#auto.commit.interval.ms=1000 如何设置为自动提交(enable.auto.commit=true),这里设置自动提交周期
spring.kafka.consumer.auto-commit-interval=1000

#自动将偏移量置为最早的
#可选值 earliest|latest|none
#earliest 
#当各分区下有已提交的offset时,从提交的offset开始消费;无提交的offset时,从头开始消费
#latest 
#当各分区下有已提交的offset时,从提交的offset开始消费;无提交的offset时,消费新产生的该分区下的数据
#none 
#topic各分区都存在已提交的offset时,从offset后开始消费;只要有一个分区不存在已提交的offset,则抛出异常
spring.kafka.consumer.auto-offset-reset=latest

#Spring Boot 日志 # SpringBoot默认使用的的日志框架是slf4j + Logback # Logback 没有 #FATAL 级别,对应着 ERROR # 日志级别从低到高 # TRACE < DEBUG < INFO < WARN < #ERROR 

## 默认配置INFO、WARN、ERROR级别的日志输出到控制台
logging.level.root=info
##配置自己的应用程序日志级别,com.xingyun 是程序的根包名称
logging.level.com.xingyun=debug
##设置其他全部的日志等级
logging.level.*=warn

#打印调试
#debug=false
#增强打印调试
#trace=false
##日志记录到文件 两者选其一,都配置的话只有logging.file 生效
#logging.path=/opt/applog
logging.file=/opt/applog/spring.log

#设置日志文件最大大小,默认为10MB 当日志文件到达10Mb时会使用压缩包保存
logging.file.max-size=10MB

#保留最近多少天的日志,超过三十天的日志就会自动删除
logging.file.max-history=7

2.4 自定义配置属性

为了在刚才的application-dev.properties文件中支持这个属性 ```

#配置约定的订阅主题

 com.xingyun.kafka.topic-name=topic.demo 

注:因为我们一般希望可以在配置文件中配置我们使用的Kafka 主题

KafkaTopicCustomProperties.java

import org.springframework.boot.context.properties.ConfigurationProperties;
//自定义前缀
@ConfigurationProperties(prefix="com.xingyun.kafka")
public class KafkaTopicCustomProperties {
	// 这种命令格式在xml中就是com.xingyun.kafka.topic-name属性值
	private String topicName;

	public String getTopicName() {
		return topicName;
	}

	public void setTopicName(String topicName) {
		this.topicName = topicName;
	}
	
	@Override
	public String toString() {
		// TODO Auto-generated method stub
		return super.toString();
	}
}

2.5 自定义属性配置激活

为了让这个属性文件被Spring Boot 识别,我们需要创建一个配置文件激活它
EnableCustomPropertiesConfig.java

import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;

import com.xingyun.properties.KafkaTopicCustomProperties;

/**
 * 配置自定义Properties属性
 * */
@EnableConfigurationProperties({
	KafkaTopicCustomProperties.class
})
@Configuration
public class EnableCustomPropertiesConfig {
	/**
	 * 静态方法是没有办法调用这个配置文件内容的
	 * 
	 * **/
}

2.6 创建我们的生产者

MyKafkaProducer.java

import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import org.apache.kafka.clients.producer.ProducerRecord;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.kafka.support.SendResult;
import org.springframework.stereotype.Service;
import org.springframework.util.concurrent.ListenableFuture;
import org.springframework.util.concurrent.ListenableFutureCallback;

import com.xingyun.properties.KafkaTopicCustomProperties;

@Service
public class MyKafkaProducer {
	
	private Logger logger=org.slf4j.LoggerFactory.getLogger(MyKafkaProducer.class);
	
	@Autowired
	private KafkaTemplate<String,String> kafkaTemplate;
	
	/**
	 * 不可以使用静态关键字修饰
	 * **/
	@Autowired
	private KafkaTopicCustomProperties kafkaTopicCustomProperties;
	
	/******** method ***********************/
	/**
	 * 第一种用法:发送普通消息没有回执
	 */
	public void sendToKafkaNormalMessage(String message) {
		
		logger.info("sending message='{}' to topic='{}'", message,kafkaTopicCustomProperties.getTopicName());
		
		// 使用Kafka直接向指定的Topic(主题)发送消息
		kafkaTemplate.send(kafkaTopicCustomProperties.getTopicName(),message);
	}
	
	/**
	 * 第二种用法:发送标准消息没有回执
	 */
	public void sendToKafkaStandardMessage(String message) {
		
		logger.info("sending message='{}' to topic='{}'", message,kafkaTopicCustomProperties.getTopicName());
		
		//构造一个标准的消息进行发送
		ProducerRecord<String, String> record = new ProducerRecord<String, String>(kafkaTopicCustomProperties.getTopicName(),message);

		kafkaTemplate.send(record);
		
	}
	
	/**
	 * 第三种用法:发送标准消息异步无阻塞
	 * **/
	public void sendToKafkaStandardMessageAsync(final String message) {
		
		// 构建待发送的消息
		ProducerRecord<String, String> record = new ProducerRecord<String, String>(kafkaTopicCustomProperties.getTopicName(), message);

		// 尝试发送消息
		ListenableFuture<SendResult<String, String>> future = kafkaTemplate.send(record);

		// 发送消息回调
		future.addCallback(new ListenableFutureCallback<SendResult<String, String>>() {
			/**
			 * 发送成功回调方法
			 */
			@Override
			public void onSuccess(SendResult<String, String> sendResultMap) {
				// TODO Auto-generated method stub
				logger.debug("\r\n send message To Kafka Async success");
			}

			/**
			 * 发送失败回调方法
			 */
			@Override
			public void onFailure(Throwable throwable) {
				// TODO Auto-generated method stub
				logger.debug("\r\n send message To Kafka Async fail");
			}
		});
	}
	
	/**
	 * 第四种用法:发送标准消息同步有阻塞
	 */
	public void sendToKafkaStandardMessageSync(String message) {
		
		//构建发送消息
		ProducerRecord<String, String> record = new ProducerRecord<String, String>(kafkaTopicCustomProperties.getTopicName(), message);
		try {
			// 使用模板发送消息
			kafkaTemplate.send(record).get(10,TimeUnit.SECONDS);
			
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			logger.error("InterruptedException:",e.toString());
			e.printStackTrace();
		} catch (ExecutionException e) {
			// TODO Auto-generated catch block
			logger.debug("ExecutionException:",e.toString());
		} catch (TimeoutException e) {
			// TODO Auto-generated catch block
			logger.debug("TimeoutException:",e.toString());
		}
	}
	
}

2.7 创建我们的消费者

MyKafkaConsumer.java

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.handler.annotation.Headers;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.stereotype.Service;

/**
 * 监听Kafka Topic,从里面取数据
 **/
@Service
public class MyKafkaConsumer {

	private Logger logger = LoggerFactory.getLogger(MyKafkaConsumer.class);

	/**
	 * 第一种场景:监听一个Kafka 主题
	 * **/
	@KafkaListener(topics = "${com.xingyun.kafka.topic-name}")
	public void receiveMessageFromKafka(@Payload byte[] message, @Headers MessageHeaders headers) {
		logger.info("receive a message from kafka server start");

		String receiveMessage = new String(message);
		logger.debug("\r\n receive a message from kafka server:{}", receiveMessage);
		// 打印headers
		headers.keySet().forEach(key -> logger.debug("{}: {}", key, headers.get(key)));

		logger.info("receive a message from kafka server end");
	}

	/**
	 * 第二种场景:监听一个Kafka 正则表达式
	 * */
//	@KafkaListener(topicPattern = "${com.xingyun.kafka.topic-name}")
//	public void receiveMessageFromKafkaTopic(@Payload byte[] message, @Headers MessageHeaders headers) {
//		logger.info("receive a message from kafka server start");
//
//		String receiveMessage = new String(message);
//		logger.debug("\r\n receive a message from kafka server:{}", receiveMessage);
//		// 打印headers
//		headers.keySet().forEach(key -> logger.debug("{}: {}", key, headers.get(key)));
//
//		logger.info("receive a message from kafka server end");
//	}
}

2.8 创建一个调用Controller

KafkaProducerTestController.java

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import com.xingyun.service.MyKafkaProducer;


@RestController
public class KafkaProducerTestController {

	private static Logger logger=LoggerFactory.getLogger(KafkaProducerTestController.class);
		
	@Autowired
	MyKafkaProducer myKafkaProducer;
	
	@GetMapping(value="/kafka/send/{message}")
	public String send(@PathVariable("message") String message) {
	
		logger.debug("send message:{}",message);
		
		//第一种用法
		myKafkaProducer.sendToKafkaNormalMessage(message);
//		//第二种用法
//		myKafkaProducer.sendToKafkaStandardMessage(message);
//		//第三种用法
//		myKafkaProducer.sendToKafkaStandardMessageAsync(message);
//		//第四种用法
//		myKafkaProducer.sendToKafkaStandardMessageSync(message);
		
		return "send message to kafka finished";
	}
}

2.9 浏览器调用

访问网址:

http://127.0.0.1:8080/kafka/send/helloworld

既可以发送消息并监听到消息

查看本文在线源码
原文:https://blog.csdn.net/hadues/article/details/88974967

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot可以轻松地集成Kafka,使得应用程序可以轻松地使用Kafka进行消息传递。 以下是Spring Boot集成Kafka的步骤: 1. 添加Kafka依赖 在pom.xml文件中添加以下依赖: ``` <dependency> <groupId>org.springframework.kafka</groupId> <artifactId>spring-kafka</artifactId> </dependency> ``` 2. 创建Kafka配置 在application.properties文件中添加以下配置: ``` spring.kafka.bootstrap-servers=localhost:9092 spring.kafka.consumer.group-id=my-group spring.kafka.consumer.auto-offset-reset=earliest spring.kafka.consumer.key-deserializer=org.apache.kafka.common.serialization.StringDeserializer spring.kafka.consumer.value-deserializer=org.apache.kafka.common.serialization.StringDeserializer spring.kafka.producer.key-serializer=org.apache.kafka.common.serialization.StringSerializer spring.kafka.producer.value-serializer=org.apache.kafka.common.serialization.StringSerializer ``` 3. 创建生产者 创建一个Kafka生产者,用于将消息发送到Kafka中: ``` @Service public class KafkaProducerService { @Autowired private KafkaTemplate<String, String> kafkaTemplate; public void sendMessage(String topic, String message) { kafkaTemplate.send(topic, message); } } ``` 4. 创建消费者 创建一个Kafka消费者,用于从Kafka中接收消息: ``` @Service public class KafkaConsumerService { @KafkaListener(topics = "my-topic") public void listen(String message) { System.out.println("Received message: " + message); } } ``` 5. 发送和接收消息 在应用程序中使用KafkaProducerService发送消息,使用KafkaConsumerService接收消息: ``` @Autowired private KafkaProducerService kafkaProducerService; public void sendMessage() { kafkaProducerService.sendMessage("my-topic", "Hello Kafka!"); } ``` 6. 运行应用程序 运行应用程序,发送和接收Kafka消息。 以上就是Spring Boot集成Kafka的步骤。通过使用Spring BootKafka,可以轻松地构建可扩展的应用程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值