Spring Cloud - 8 (Spring Cloud Stream)

Spring Cloud Stream


Kafka


官方网页

Apache Kafka

主要用途

  • 消息中间件
  • 流式计算处理
  • 日志

下载地址:Apache Kafka

执行脚本目录 /bin

windows 在其单独的目录

快速上手

下载并且解压kafka压缩包

运行服务

以Windows为例,首先打开cmd:

1.  启动zookeeper:

bin\windows\zookeeper-server-start.bat config\zookeeper.properties

2.  启动kafka:

bin\windows\kafka-server-start.bat config\server.properties

创建主题topic

bin\windows\kafka-topics.bat --create --bootstrap-server localhost:9092 --replication-factor 1 --partitions 1 --topic cloud

cloud

生产者:发送消息

\bin\windows>kafka-console-producer.bat --broker-list localhost:9092 --topic cloud
>hello

消费者:接收消息

\bin\windows>kafka-console-consumer.bat --bootstrap-server localhost:9092 --topic cloud --from-beginning
hello

同类产品比较

  • ActiveMQ:JMS(Java Message Service)规范实现
  • RabbitMQ:AMQP(Advanced Message Queue Protocol)规范实现
  • Kafka:并非某种规范实现,它的灵活和性能相对是优势

Spring Kafka


import java.util.Properties;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.clients.producer.RecordMetadata;
import org.apache.kafka.common.serialization.StringSerializer;

public class TestKafka {

	public static void main(String[] args) throws ExecutionException, InterruptedException {

		Properties properties = new Properties();

		properties.setProperty("bootstrap.servers", "localhost:9092");
		properties.setProperty("key.serializer", StringSerializer.class.getName());
		properties.setProperty("value.serializer", StringSerializer.class.getName());

		// 创建 Kafka Producer
		KafkaProducer<String, String> kafkaProducer = new KafkaProducer(properties);

		// 创建Kafka消息 = ProducerRecord
		String topic = "cloud";

		Integer partition = 0;

		Long timestamp = System.currentTimeMillis();

		String key = "message-key";
		String value = "how are you!";

		ProducerRecord<String, String> record = new ProducerRecord<String, String>(topic, partition, timestamp, key, value);

		// 发送kafka消息
		Future<RecordMetadata> metadataFuture = kafkaProducer.send(record);

		// 强制执行
		metadataFuture.get();

	}

}


 

官方文档:Spring for Apache Kafka

设计模式

Spring社区对data(Spring-data)操作,有一个基本的模式,Template模式:

  • JDBC:JdbcTemplate
  • Redis:RedisTemplate
  • Kafka:KafkaTemplate
  • JMS:JmsTemplate
  • Rest:RestTemplate

XXXTemplate一定实现XXXOpeations

KafkaTemplate implements KafkaOpeations

Maven依赖

<dependency>

 <groupId>org.springframework.kafka</groupId>

<artifactId>spring-kafka</artifactId>

</dependency>

自动装配器: KafkaAutoConfiguration

其中KafkaTemplate会被自动装配:

import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.kafka.KafkaProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.kafka.core.ProducerFactory;
import org.springframework.kafka.support.ProducerListener;

@Configuration
public class KafkaAutoConfiguration {
	
	 private final KafkaProperties properties;

    public KafkaAutoConfiguration(KafkaProperties properties) {
        this.properties = properties;
    }
	    
	@Bean
	@ConditionalOnMissingBean(KafkaTemplate.class)
	public KafkaTemplate<?,?> kafkaTemplate(ProducerFactory<Object,Object> kafkaProducerFactory,
	
	    ProducerListener<Object,Object> kafkaProducerListener){
	    KafkaTemplate<Object,Object> kafkaTemplate = new KafkaTemplate<Object,Object>(kafkaProducerFactory);
	
	    kafkaTemplate.setProducerListener(kafkaProducerListener);
	    kafkaTemplate.setDefaultTopic(this.properties.getTemplate().getDefaultTopic());
	
	    return kafkaTemplate;
	}
}

创建生产者

增加生产者配置

application.properties

   全局配置:

    ### Kafka生产者配置     

    spring.kafka.producer.bootstrapServers = localhost:9092

### Kafka生产者配置

# spring.kafka.producer.bootstrapServers = localhost:9092

spring.kafka.producer.keySerializer = org.apache.kafka.common.serialization.StringSerializer

spring.kafka.producer.valueSerializer = org.apache.kafka.common.serialization.StringSerializer
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class KafkaProducerController {

	private final KafkaTemplate<String, String> kafkaTemplate;

	private final String topic;

	@Autowired
	public KafkaProducerController(KafkaTemplate<String, String> kafkaTemplate, @Value("${kafka.topic}") String topic) {

		this.kafkaTemplate = kafkaTemplate;
		this.topic = topic;
	}

	@PostMapping("/message/send")
	public Boolean sendMessage(@RequestParam(required=false)String message) {
		kafkaTemplate.send(topic, message);
		return true;
	}

}

创建消费者

增加消费者配置

### Kafka消费者配置
spring.kafka.consumer.groupId = cloud-1

spring.kafka.consumer.keyDeserializer = org.apache.kafka.common.serialization.StringDeserializer

spring.kafka.consumer.valueDeserializer = org.apache.kafka.common.serialization.StringDeserializer
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.stereotype.Component;

@Component
public class KafkaConsumerListener {

	@KafkaListener(topics = "${kafka.topic}")
	public void onMessage(String message) {

		System.out.print("kafka 消费者监听器,接收到消息:" + message);

	}
}

Spring Cloud Stream


基本概念

  • Source:来源,近义词:Producer、Publisher
  • Sink:接收器,近义词:Consumer、Subscriber
  • Processor:对于上流而言是Sink,对于下流而言是Source

Reactive Streams:

  • Publisher
  • Subscriber
  • Processor

Spring Cloud Stream Binder:kafka

定义标准消息发送源

@Component
@EnableBinding(Source.class)
public class MessageProducerBean {

    @Autowired
    @Qualifier(Source.OUTPUT)
    private MessageChannel messageChannel; 
    
    @Autowired
    private Source source;
    
    
    public void send(String message) {
        messageChannel.send(MessageBuilder.withPayload(message).build());
        source.output().send(MessageBuilder.withPayload(message).build());
    }

}

注入

@RestController
public class KafkaProducerController {

    private final KafkaTemplate<String, String> kafkaTemplate;

    private final MessageProducerBean messageProducerBean;

    private final String topic;

    @Autowired
    public KafkaProducerController(KafkaTemplate<String, String> kafkaTemplate, 
            @Value("${kafka.topic}") String topic,
            MessageProducerBean messageProducerBean) {

        this.kafkaTemplate = kafkaTemplate;
        this.messageProducerBean = messageProducerBean;
        this.topic = topic;
    }

    @PostMapping("/message/send")
    public Boolean sendMessage(@RequestParam(required=false)String message) {
        kafkaTemplate.send(topic, message);
        return true;
    }
    
    @GetMapping("/message/output/send")
    public Boolean outputSend(@RequestParam String message) {
        messageProducerBean.send(message);
        return true;
    }    
    

}

实现标准Sink监听

@Component
@EnableBinding(Sink.class)
public class MessageConsumerBean {

    @Autowired
    @Qualifier(Sink.INPUT)
    private SubscribableChannel subscribableChannel;
    
    @Autowired
    private Sink sink;

    @PostConstruct
    public void init() {
        subscribableChannel.subscribe(new MessageHandler() {
            
            @Override
            public void handleMessage(Message<?> message) throws MessagingException {
                System.out.println("init: "+message.getPayload());
                
            }
        });
    }
    
    @ServiceActivator(inputChannel = Sink.INPUT)
    public void serviceActivator(Object message) {
        System.out.println("serviceActivator: "+message);
    }
    
    @StreamListener(Sink.INPUT)
    public void streamListener(String message) {
        System.out.println("streamListener: "+message);
    }
    
}

自定义标准消息发送源

public interface MySource {
    
    String MYOUTPUT = "myoutput";

    
    @Output(MySource.MYOUTPUT)
    MessageChannel myoutput();

}
@Component
@EnableBinding(MySource.class)
public class MyMessageProducerBean {

	@Autowired
	@Qualifier(MySource.MYOUTPUT)
	private MessageChannel messageChannel; 
	
	@Autowired
	private MySource mySource;
	
	
	public void send(String message) {
		messageChannel.send(MessageBuilder.withPayload(message).build());
		mySource.myoutput().send(MessageBuilder.withPayload(message).build());
	}

}

自定义Sink监听

public interface MySink {

    String MYINPUT = "myinput";

    @Input(MySink.MYINPUT)
    SubscribableChannel input();

}

@Component
@EnableBinding(MySink.class)
public class MyMessageConsumerBean {

    @Autowired
    @Qualifier(MySink.MYINPUT)
    private SubscribableChannel subscribableChannel;
    
    @Autowired
    private MySink mySink;

    @PostConstruct
    public void init() {
        subscribableChannel.subscribe(new MessageHandler() {
            
            @Override
            public void handleMessage(Message<?> message) throws MessagingException {
                System.out.println("my - Sink: "+message.getPayload());
                
            }
        });
    }
    
    @ServiceActivator(inputChannel = MySink.MYINPUT)
    public void serviceActivator(Object message) {
        System.out.println("my - serviceActivator: "+message);
    }
    
    @StreamListener(MySink.MYINPUT)
    public void streamListener(String message) {
        System.out.println("my - streamListener: "+message);
    }
    
}

配置项

kafka.topic.my = mytopic
spring.cloud.stream.bindings.myoutput.destination=${kafka.topic.my}
spring.cloud.stream.bindings.myinput.destination=${kafka.topic.my}

Spring Cloud Stream Binder:rabbit


重构Kafka工程,删除强依赖

Stream-kafka实现源码:https://pan.baidu.com/s/1RX5W2wMj4h_SKDkjlPQHkA 提取码:lwak 
 

Stream-rabbit实现源码:https://pan.baidu.com/s/1AX6asvmATN9-dYrhIIfS7w 提取码:dsc5 
 

  • 6
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
【2021年,将Spring全家桶系列课程进行Review,修复顺序等错误。进入2022年,将Spring的课程进行整理,整理为案例精讲的系列课程,并新增高级的Spring Security等内容,通过手把手一步步教你从零开始学会应用Spring,课件将逐步进行上传,敬请期待】 本课程是Spring案例精讲课程的第四部分Spring CloudSpring案例精讲课程以真实场景、项目实战为导向,循序渐进,深入浅出的讲解Java网络编程,助力您在技术工作中更进一步。 本课程聚焦Spring Cloud的核心知识点:注册中心、服务提供者与消费者、服务的调用OpenFeign、Hystrix监控、服务网关gateway、消息驱动的微服务Spring Cloud Stream、分布式集群、分布式配置中心的案例介绍, 快速掌握Spring Cloud的核心知识,快速上手,为学习及工作做好充足的准备。 由于本课程聚焦于案例,即直接上手操作,对于Spring的原理等不会做过多介绍,希望了解原理等内容的需要通过其他视频或者书籍去了解,建议按照该案例课程一步步做下来,之后再去进一步回顾原理,这样能够促进大家对原理有更好的理解。【通过Spring全家桶,我们保证你能收获到以下几点】 1、掌握Spring全家桶主要部分的开发、实现2、可以使用Spring MVC、Spring Boot、Spring CloudSpring Data进行大部分的Spring开发3、初步了解使用微服务、了解使用Spring进行微服务的设计实现4、奠定扎实的Spring技术,具备了一定的独立开发的能力  【实力讲师】 毕业于清华大学软件学院软件工程专业,曾在Accenture、IBM等知名外企任管理及架构职位,近15年的JavaEE经验,近8年的Spring经验,一直致力于架构、设计、开发及管理工作,在电商、零售、制造业等有丰富的项目实施经验  【本课程适用人群】如果你是一定不要错过!  适合于有JavaEE基础的,如:JSP、JSTL、Java基础等的学习者没有基础的学习者跟着课程可以学习,但是需要补充相关基础知识后,才能很好的参与到相关的工作中。 【Spring全家桶课程共包含如下几门】 

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值