kafka与Spring的集成
准备工作
kafka版本:kafka_2.10-0.10.1.0
spring版本:spring4.3
配置文件
pom文件配置(也可以直接下载jar包)
Kafka和spring集成的支持类库,spring和kafka通信监听
- <dependency>
- <groupId>org.springframework.integration</groupId>
- <artifactId>spring-integration-kafka</artifactId>
- <version>1.3.0.RELEASE</version>
- </dependency>
kafka发送消息以及接受消息使用的类库
- <dependency>
- <groupId>org.apache.kafka</groupId>
- <artifactId>kafka-clients</artifactId>
- <version>0.10.1.0</version>
- </dependency>
使用高版本是因为低版本无法支持kafka监听,spring和kafka集成不好
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-webmvc</artifactId>
- <version>4.3.0.RELEASE</version>
- </dependency>
kafka自带监听器,依赖于spring,所以需要和pring-integration-kafka结合使用
- <dependency>
- <groupId>org.springframework.kafka</groupId>
- <artifactId>spring-kafka</artifactId>
- <version>1.0.0.RC1</version>
- </dependency>
producer配置
1.如果你的topic没有设置名称,按照默认的topic的名字生成对应的数据文件夹。
2.producerListener用来判断kafka发送数据是否成功以及发送反馈信息。
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans.xsd
- http://www.springframework.org/schema/context
- http://www.springframework.org/schema/context/spring-context.xsd">
- <!-- 定义producer的参数 -->
- <bean id="producerProperties" class="java.util.HashMap">
- <constructor-arg>
- <map>
- <entry key="bootstrap.servers" value="localhost:7000" />
- <entry key="group.id" value="0" />
- <entry key="retries" value="1" />
- <entry key="batch.size" value="16384" />
- <entry key="linger.ms" value="1" />
- <entry key="buffer.memory" value="33554432" />
- <entry key="key.serializer"
- value="org.apache.kafka.common.serialization.StringSerializer" />
- <entry key="value.serializer"
- value="org.apache.kafka.common.serialization.StringSerializer" />
- </map>
- </constructor-arg>
- </bean>
- <!-- 创建kafkatemplate需要使用的producerfactory bean -->
- <bean id="producerFactory"
- class="org.springframework.kafka.core.DefaultKafkaProducerFactory">
- <constructor-arg>
- <ref bean="producerProperties" />
- </constructor-arg>
- </bean>
- <!-- 创建kafkatemplate bean,使用的时候,只需要注入这个bean,即可使用template的send消息方法 -->
- <bean id="KafkaTemplate" class="org.springframework.kafka.core.KafkaTemplate">
- <constructor-arg ref="producerFactory" />
- <constructor-arg name="autoFlush" value="true" />
- <property name="defaultTopic" value="defaultTopic" />
- <property name="producerListener" ref="producerListener"/>
- </bean>
- <bean id="producerListener" class="com.git.kafka.producer.KafkaProducerListener" />
- </beans>
consumer配置
1.使用kafka的listener进行消息消费监听,如果有消费消息进入会自动调用OnMessage方法进行消息消费以及后续业务处理。
2.如果要配置多个topic,需要创建新的消费者容器,然后统一指向listner的消息处理类,统一让这个类进行后续业务处理。
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:context="http://www.springframework.org/schema/context"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
- http://www.springframework.org/schema/tx
- http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
- http://www.springframework.org/schema/jee
- http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
- http://www.springframework.org/schema/context
- http://www.springframework.org/schema/context/spring-context-3.0.xsd">
- <!-- 定义consumer的参数 -->
- <bean id="consumerProperties" class="java.util.HashMap">
- <constructor-arg>
- <map>
- <entry key="bootstrap.servers" value="127.0.0.1:7000"/>
- <entry key="group.id" value="0"/>
- <entry key="enable.auto.commit" value="false"/>
- <entry key="auto.commit.interval.ms" value="1000"/>
- <entry key="session.timeout.ms" value="15000"/>
- <entry key="key.deserializer" value="org.apache.kafka.common.serialization.StringDeserializer"/>
- <entry key="value.deserializer" value="org.apache.kafka.common.serialization.StringDeserializer"/>
- </map>
- </constructor-arg>
- </bean>
- <!-- 创建consumerFactory bean -->
- <bean id="consumerFactory" class="org.springframework.kafka.core.DefaultKafkaConsumerFactory">
- <constructor-arg>
- <ref bean="consumerProperties"/>
- </constructor-arg>
- </bean>
- <!-- 实际执行消息消费的类 -->
- <bean id="messageListernerConsumerService" class="com.git.kafka.consumer.KafkaConsumerServer"/>
- <!-- 消费者容器配置信息 -->
- <bean id="containerProperties_trade" class="org.springframework.kafka.listener.config.ContainerProperties">
- <constructor-arg value="order_test_topic"/>
- <property name="messageListener" ref="messageListernerConsumerService"/>
- </bean>
- <bean id="containerProperties_other" class="org.springframework.kafka.listener.config.ContainerProperties">
- <constructor-arg value="other_test_topic"/>
- <property name="messageListener" ref="messageListernerConsumerService"/>
- </bean>
- <!-- 创建messageListenerContainer bean,使用的时候,只需要注入这个bean -->
- <bean id="messageListenerContainer_trade" class="org.springframework.kafka.listener.KafkaMessageListenerContainer"
- init-method="doStart">
- <constructor-arg ref="consumerFactory"/>
- <constructor-arg ref="containerProperties_trade"/>
- </bean>
- <bean id="messageListenerContainer_other" class="org.springframework.kafka.listener.KafkaMessageListenerContainer"
- init-method="doStart">
- <constructor-arg ref="consumerFactory"/>
- <constructor-arg ref="containerProperties_other"/>
- </bean>
- </beans>
applicationContext配置
- <import resource="classpath:kafkaConsumer.xml" />
- <import resource="classpath:kafkaProducer.xml" />
具体实现
constant.java //常量类
- package com.git.kafka.constant;
- /**
- * kafkaMessageConstant
- * @author wangb
- *
- */
- public class KafkaMesConstant {
- public static final String SUCCESS_CODE = "00000";
- public static final String SUCCESS_MES = "成功";
- /*kakfa-code*/
- public static final String KAFKA_SEND_ERROR_CODE = "30001";
- public static final String KAFKA_NO_RESULT_CODE = "30002";
- public static final String KAFKA_NO_OFFSET_CODE = "30003";
- /*kakfa-mes*/
- public static final String KAFKA_SEND_ERROR_MES = "发送消息超时,联系相关技术人员";
- public static final String KAFKA_NO_RESULT_MES = "未查询到返回结果,联系相关技术人员";
- public static final String KAFKA_NO_OFFSET_MES = "未查到返回数据的offset,联系相关技术人员";
- }
KafkaConsumerServer.java //消费者监听
- package com.git.kafka.consumer;
- import org.apache.kafka.clients.consumer.ConsumerRecord;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import org.springframework.kafka.listener.MessageListener;
- /**
- * kafka监听器启动
- * 自动监听是否有消息需要消费
- * @author wangb
- *
- */
- public class KafkaConsumerServer implements MessageListener<String, String> {
- protected final Logger LOG = LoggerFactory.getLogger("kafkaConsumer");
- /**
- * 监听器自动执行该方法
- * 消费消息
- * 自动提交offset
- * 执行业务代码
- * (high level api 不提供offset管理,不能指定offset进行消费)
- */
- @Override
- public void onMessage(ConsumerRecord<String, String> record) {
- LOG.info("=============kafkaConsumer开始消费=============");
- String topic = record.topic();
- String key = record.key();
- String value = record.value();
- long offset = record.offset();
- int partition = record.partition();
- LOG.info("-------------topic:"+topic);
- LOG.info("-------------value:"+value);
- LOG.info("-------------key:"+key);
- LOG.info("-------------offset:"+offset);
- LOG.info("-------------partition:"+partition);
- LOG.info("~~~~~~~~~~~~~kafkaConsumer消费结束~~~~~~~~~~~~~");
- }
- }
kafkaProducerListener.java //生产者监听-打印日志
- package com.git.kafka.producer;
- import org.apache.kafka.clients.producer.RecordMetadata;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import org.springframework.kafka.support.ProducerListener;
- /**
- * kafkaProducer监听器,在producer配置文件中开启
- * @author wangb
- *
- */
- @SuppressWarnings("rawtypes")
- public class KafkaProducerListener implements ProducerListener{
- protected final Logger LOG = LoggerFactory.getLogger("kafkaProducer");
- /**
- * 发送消息成功后调用
- */
- @Override
- public void onSuccess(String topic, Integer partition, Object key,
- Object value, RecordMetadata recordMetadata) {
- LOG.info("==========kafka发送数据成功(日志开始)==========");
- LOG.info("----------topic:"+topic);
- LOG.info("----------partition:"+partition);
- LOG.info("----------key:"+key);
- LOG.info("----------value:"+value);
- LOG.info("----------RecordMetadata:"+recordMetadata);
- LOG.info("~~~~~~~~~~kafka发送数据成功(日志结束)~~~~~~~~~~");
- }
- /**
- * 发送消息错误后调用
- */
- @Override
- public void onError(String topic, Integer partition, Object key,
- Object value, Exception exception) {
- LOG.info("==========kafka发送数据错误(日志开始)==========");
- LOG.info("----------topic:"+topic);
- LOG.info("----------partition:"+partition);
- LOG.info("----------key:"+key);
- LOG.info("----------value:"+value);
- LOG.info("----------Exception:"+exception);
- LOG.info("~~~~~~~~~~kafka发送数据错误(日志结束)~~~~~~~~~~");
- exception.printStackTrace();
- }
- /**
- * 方法返回值代表是否启动kafkaProducer监听器
- */
- @Override
- public boolean isInterestedInSuccess() {
- LOG.info("///kafkaProducer监听器启动///");
- return true;
- }
- }
KafkaProducerServer.java //生产者
- package com.git.kafka.producer;
- import java.util.HashMap;
- import java.util.Map;
- import java.util.Random;
- import java.util.concurrent.ExecutionException;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.kafka.core.KafkaTemplate;
- import org.springframework.kafka.support.SendResult;
- import org.springframework.stereotype.Component;
- import org.springframework.util.concurrent.ListenableFuture;
- import com.alibaba.fastjson.JSON;
- import com.git.kafka.constant.KafkaMesConstant;
- /**
- * kafkaProducer模板
- * 使用此模板发送消息
- * @author wangb
- *
- */
- @Component
- public class KafkaProducerServer{
- @Autowired
- private KafkaTemplate<String, String> kafkaTemplate;
- /**
- * kafka发送消息模板
- * @param topic 主题
- * @param value messageValue
- * @param ifPartition 是否使用分区 0是\1不是
- * @param partitionNum 分区数 如果是否使用分区为0,分区数必须大于0
- * @param role 角色:bbc app erp...
- */
- public Map<String,Object> sndMesForTemplate(String topic, Object value, String ifPartition,
- Integer partitionNum, String role){
- String key = role+"-"+value.hashCode();
- String valueString = JSON.toJSONString(value);
- if(ifPartition.equals("0")){
- //表示使用分区
- int partitionIndex = getPartitionIndex(key, partitionNum);
- ListenableFuture<SendResult<String, String>> result = kafkaTemplate.send(topic, partitionIndex, key, valueString);
- Map<String,Object> res = checkProRecord(result);
- return res;
- }else{
- ListenableFuture<SendResult<String, String>> result = kafkaTemplate.send(topic, key, valueString);
- Map<String,Object> res = checkProRecord(result);
- return res;
- }
- }
- /**
- * 根据key值获取分区索引
- * @param key
- * @param partitionNum
- * @return
- */
- private int getPartitionIndex(String key, int partitionNum){
- if (key == null) {
- Random random = new Random();
- return random.nextInt(partitionNum);
- }
- else {
- int result = Math.abs(key.hashCode())%partitionNum;
- return result;
- }
- }
- /**
- * 检查发送返回结果record
- * @param res
- * @return
- */
- @SuppressWarnings("rawtypes")
- private Map<String,Object> checkProRecord(ListenableFuture<SendResult<String, String>> res){
- Map<String,Object> m = new HashMap<String,Object>();
- if(res!=null){
- try {
- SendResult r = res.get();//检查result结果集
- /*检查recordMetadata的offset数据,不检查producerRecord*/
- Long offsetIndex = r.getRecordMetadata().offset();
- if(offsetIndex!=null && offsetIndex>=0){
- m.put("code", KafkaMesConstant.SUCCESS_CODE);
- m.put("message", KafkaMesConstant.SUCCESS_MES);
- return m;
- }else{
- m.put("code", KafkaMesConstant.KAFKA_NO_OFFSET_CODE);
- m.put("message", KafkaMesConstant.KAFKA_NO_OFFSET_MES);
- return m;
- }
- } catch (InterruptedException e) {
- e.printStackTrace();
- m.put("code", KafkaMesConstant.KAFKA_SEND_ERROR_CODE);
- m.put("message", KafkaMesConstant.KAFKA_SEND_ERROR_MES);
- return m;
- } catch (ExecutionException e) {
- e.printStackTrace();
- m.put("code", KafkaMesConstant.KAFKA_SEND_ERROR_CODE);
- m.put("message", KafkaMesConstant.KAFKA_SEND_ERROR_MES);
- return m;
- }
- }else{
- m.put("code", KafkaMesConstant.KAFKA_NO_RESULT_CODE);
- m.put("message", KafkaMesConstant.KAFKA_NO_RESULT_MES);
- return m;
- }
- }
- }
KafkaProducerTest.java //kafka生产者测试(消费者使用spring启动监听,自动执行onMessage方法)
- package com.git.test;
- import java.util.Map;
- import com.git.kafka.producer.KafkaProducerServer;
- public class KafkaProducerTest {
- public static void main(String[] args) {
- KafkaProducerServer kafkaProducer = new KafkaProducerServer();
- String topic = "orderTopic";
- String value = "test";
- String ifPartition = "0";
- Integer partitionNum = 3;
- String role = "test";//用来生成key
- Map<String,Object> res = kafkaProducer.sndMesForTemplate
- (topic, value, ifPartition, partitionNum, role);
- System.out.println("测试结果如下:===============");
- String message = (String)res.get("message");
- String code = (String)res.get("code");
- System.out.println("code:"+code);
- System.out.println("message:"+message);
- }
- }
具体项目代码
项目地址:https://git.oschina.net/wsmd/kafka-0.10-demo
kafka与Spring的集成的更多相关文章
- Spring boot 集成Kafka
搭建Kafka集群,参考: https://www.cnblogs.com/jonban/p/kafka.html 源码示例如下: 1.新建 Maven 项目 kafka 2.pom.xml < ...
- Kafka 入门和 Spring Boot 集成
目录 Kafka 入门和 Spring Boot 集成 标签:博客 概述 应用场景 基本概念 基本结构 和Spring Boot 集成 集成概述 集成环境 kafka 环境搭建 Spring Boot ...
- Spring 对Apache Kafka的支持与集成
1. 引言 Apache Kafka 是一个分布式的.容错的流处理系统.在本文中,我们将介绍Spring对Apache Kafka的支持,以及原生Kafka Java客户端Api 所提供的抽象级别. ...
- quartz与spring进行集成
上一篇将了quartz框架的使用,spring同样也提供了对quartz的集成.这次就尝试一下在spring中集成quartz. 要在spring中使用job,Trigger和Scheduler,就要 ...
- 在Spring下集成ActiveMQ
1.参考文献 Spring集成ActiveMQ配置 Spring JMS异步发收消息 ActiveMQ 2.环境 在前面的一篇ActiveMQ入门实例中我们实现了消息的异步传送,这篇博文将如何在spr ...
- maven,spring,mybatis集成错误
maven,spring,mybatis集成的时候单元测试junit测试没问题,但mvn jetty:run 就报错误 错误: org.apache.ibatis.binding.BindingExc ...
- Spring Boot集成Jasypt安全框架
Jasypt安全框架提供了Spring的集成,主要是实现 PlaceholderConfigurerSupport类或者其子类. 在Sring 3.1之后,则推荐使用PropertySourcesPl ...
- Struts2+Spring+Ibatis集成合并
上一篇博客讲述了Struts2+Spring的集成合并,主要是利用了一个中间jar包,这篇博客在加上Ibatis持久层框架,三个框架进行合并.其中Struts2和Spring部分和前边的一样,主要是讲 ...
- spring+springMVC集成(annotation方式)
spring+springMVC集成(annotation方式) SpringMVC+Spring4.0+Hibernate 简单的整合 MyBatis3整合Spring3.SpringMVC3
随机推荐
- kendo ui中grid页面参数问题
kendo ui 中grid 算是最长用的控件之一,当使用分页效果时,我们要传递分页参数与自己定义的参数如: var dataSource = new kendo.data.DataSource({ ...
- Three Families
http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&p ...
- 自己实现一个SQL解析引擎
自己实现一个SQL解析引擎 功能:将用户输入的SQL语句序列转换为一个可运行的操作序列,并返回查询的结果集. SQL的解析引擎包含查询编译与查询优化和查询的执行,主要包含3个步骤: 查询分析: 制定逻 ...
- grub2手动引导ubuntu
測试机OS为ubuntu 14.04.1 LTS x86_64 磁盘分区情况为: Filesystem 1K-blocks Used Available Use% Mounted on ...
- listener笔记
listener 分四步: 在被观察者类中创建 onXXListener Interface,包含一个方法:xxxListener(object o),参数根据需要观察者需要设定. public in ...
- Android入门2:从GridView控件使用到自定义Adapter
在日常手机app的使用中,出现频率最高的便是ListView和GridView.ListView的例子是微信主界面,而GridView的例子则是支付宝的主界面,不明白的小伙伴打开手机便一目了然.然而这 ...
- IOS中对于一些控件的抖动效果
这两天在网上看到一个帖子讨论关于有些app 输入账密时候 错误的话会有抖动效果出现,然后自己琢磨了下如何实现,下面上代码!!! 首先 写一个UIView的分类 #import <UIKit/UI ...
- MYSQLI DEMO
1.Select // DEMO mysqli连接方式参考 $db = new mysqli("localhost:3306", "root", "& ...
- Java系列--目录
因工作项目的需要,从C#转Java也有很长一段时间了,决定记载归纳一下这半年到底学了什么,到了一个什么程度,当然其间可能会有一些关于.NET的对比. 这是这个系列的目录,我准备按照我的归纳学习点来写, ...
- Oracle11g R2学习系列 之三教程选择
工欲善其事必先利其器,选择一本入门教程也是很重要的,本人使用的也是这位同事推荐的电子工业出版社的<<Oracle 实用教程(第3版)>>郑阿奇主编,可以至这里购买到,我个人还是 ...