我们首先创建一个生产者服务。这里以一个商品价格服务为例,这个微服务可以对商品-价格信息进行增删改查,当有商品-价格信息被更新或删除,则该微服务发送消息,告诉其他调用它的系统这条信息已经被修改。

配置pom.xml

首先,在pom.xml中添加spring-cloud-stream和spring-cloud-starter-stream-kafka两个依赖

<!-- Spring cloud: stream -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream</artifactId>
</dependency>
<!-- Spring cloud starter: kafka -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-kafka</artifactId>
</dependency>

此外,它还是一个Eureka Client和Config Client,如何配置Eureka Client和Config Client请看前面章节。

配置发射器(source),通道(channel),绑定器(binder)及Application

public interface ProductPriceSource {
@Output("productPriceOutput")
MessageChannel productPriceOutput();
}

[注] 这里创建了一个叫“productPriceOutput”的自定义发射通道,如果不使用自定义,可以直接使用org.springframework.cloud.stream.messaging.Source接口及叫output的发射通道(下面的yml文件会讲如何配置)。

@Component
public class ProductPriceMessageSender { @Autowired
private ProductPriceSource source; private static final Logger logger = LoggerFactory.getLogger(ProductPriceMessageSender.class); /**
* The product is expired and need to send kafka message to consumer service to remove it from cache(redis).
*
* @param productId
*/
public void sendMessage(Long productId) {
logger.info(String.format(">>>>> Sending Kafka message: [productId = %s].", productId.toString()));
source.productPriceOutput().send(MessageBuilder.withPayload(productId).build());
}
}

[注] 这里配置了一个发射器bean,当有商品-价格信息被更新或删除,则调用该bean,把消息发布到消息队列。

@SpringBootApplication
@EnableBinding({ ProductPriceSource.class })
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}

[注] Application中加入@EnableBinding注解,并把定义好的发射通道(output)或接收通道(input)绑定到该服务中。可以绑定多个。

配置application.yml

## Spring info
spring:
# Stream/Kafka info
cloud:
stream:
bindings:
# output -> productPriceOutput (自定义通道)
productPriceOutput:
# 要写入消息的消息队列的名称
destination: productPriceTopic
# 发送和接收消息类型
content-type: application/json
# 使用kafka作为消息总线
kafka:
binder:
# 运行着kafka服务器的网络地址
brokers: www.mytools.com

API及其他业务逻辑

@Controller
@RequestMapping("pp")
public class ProductPriceController { @Autowired
private ProductPriceService productPriceService; @GetMapping(value = "find/all")
@ResponseBody
public List<ProductPriceEntity> findAll() {
return productPriceService.findAll();
} @GetMapping(value = "find/productId/{productId}")
@ResponseBody
public ProductPriceEntity find(@PathVariable String productId) {
return productPriceService.findById(Long.valueOf(productId));
} @GetMapping(value = "add/productId/{productId}/product/{product}/price/{price}")
@ResponseBody
public String save(@PathVariable String productId, @PathVariable String product, @PathVariable String price) {
return productPriceService.save(Long.valueOf(productId), product, new BigDecimal(price));
} @GetMapping(value = "update/productId/{productId}/product/{product}/price/{price}")
@ResponseBody
public String update(@PathVariable String productId, @PathVariable String product, @PathVariable String price) {
return productPriceService.update(Long.valueOf(productId), product, new BigDecimal(price));
} @GetMapping(value = "delete/productId/{productId}")
@ResponseBody
public String delete(@PathVariable String productId) {
return productPriceService.delete(Long.valueOf(productId));
}
}

[注] 这里创建了几个常规的,包括增删改查的API。

@Service
public class ProductPriceService { private static final Map<Long, ProductPriceEntity> db = new ConcurrentHashMap<>(); static {
ProductPriceEntity row1 = new ProductPriceEntity(1L, "Apple", new BigDecimal("8.5"));
ProductPriceEntity row2 = new ProductPriceEntity(2L, "Watermelon", new BigDecimal("2.2"));
ProductPriceEntity row3 = new ProductPriceEntity(3L, "Grape", new BigDecimal("6.8"));
db.put(1L, row1);
db.put(2L, row2);
db.put(3L, row3);
} @Autowired
private ProductPriceMessageSender sender; public List<ProductPriceEntity> findAll() { List<ProductPriceEntity> results = new ArrayList<>();
results.addAll(db.values()); return results;
} public ProductPriceEntity findById(Long productId) {
return db.get(productId);
} public String save(Long productId, String product, BigDecimal price) {
if (db.containsKey(productId)) {
return String.format("[WARN] Product which productId = %s already exists in DB.", productId.toString());
} else {
ProductPriceEntity param = new ProductPriceEntity(productId, product, price);
db.put(productId, param);
return String.format("Save %s completed.", param);
}
} public String update(Long productId, String product, BigDecimal price) {
if (db.containsKey(productId)) {
ProductPriceEntity param = new ProductPriceEntity(productId, product, price);
db.put(productId, param);
// [UPDATE] send to kafka
sender.sendMessage(productId);
return String.format("Update %s completed.", param);
} else {
return String.format("[WARN] No product which productId = %s in DB.", productId.toString());
}
} public String delete(Long productId) {
if (db.containsKey(productId)) {
ProductPriceEntity result = db.remove(productId);
// [DELETE] send to kafka
sender.sendMessage(productId);
return String.format("Delete %s completed.", result.toString());
} else {
return String.format("[WARN] No product which productId = %s in DB.", productId.toString());
}
}
}

[注] 这里使用一个Map来模拟DB。并且当有商品-价格信息被更新或删除时,才调用ProductPriceMessageSender发送消息。ProductPriceEntity的代码如下:

public class ProductPriceEntity implements Serializable {

    private static final long serialVersionUID = 1L;

    private Long productId;

    private String product;

    private BigDecimal price;

    public ProductPriceEntity() {
} public ProductPriceEntity(Long productId, String product, BigDecimal price) {
super();
this.productId = productId;
this.product = product;
this.price = price;
} public Long getProductId() {
return productId;
} public void setProductId(Long productId) {
this.productId = productId;
} public String getProduct() {
return product;
} public void setProduct(String product) {
this.product = product;
} public BigDecimal getPrice() {
return price;
} public void setPrice(BigDecimal price) {
this.price = price;
} @Override
public String toString() {
return "ProductPriceEntity [productId=" + productId + ", product=" + product + ", price=" + price + "]";
}
}

ProductPriceEntity

Input and Output to a broker,

Spring Cloud(7.2):配置Producer Server的更多相关文章

  1. Spring Cloud Config(配置中心)

    每天学习一点点 编程PDF电子书.视频教程免费下载:http://www.shitanlife.com/code 一.简介 Spring Cloud Config为分布式系统中的外部配置提供服务器和客 ...

  2. spring cloud config将配置存储在数据库中

    Spring Cloud Config Server最常见是将配置文件放在本地或者远程Git仓库,放在本地是将将所有的配置文件统一写在Config Server工程目录下,如果需要修改配置,需要重启c ...

  3. 跟我学SpringCloud | 第六篇:Spring Cloud Config Github配置中心

    SpringCloud系列教程 | 第六篇:Spring Cloud Config Github配置中心 Springboot: 2.1.6.RELEASE SpringCloud: Greenwic ...

  4. Spring Cloud Config 实现配置中心,看这一篇就够了

    Spring Cloud Config 是 Spring Cloud 家族中最早的配置中心,虽然后来又发布了 Consul 可以代替配置中心功能,但是 Config 依然适用于 Spring Clou ...

  5. spring cloud 2.x版本 Eureka Server服务注册中心教程

    本文采用Spring cloud本文为2.1.8RELEASE,version=Greenwich.SR3 1.创建服务注册中心 1.1 新建Spring boot工程:eureka-server 1 ...

  6. Spring Cloud Config的配置中心获取不到最新配置信息的问题

    Spring Cloud Config的配置中心获取不到最新配置信息的问题 http://blog.didispace.com/spring-cloud-tips-config-tmp-clear/

  7. Spring Cloud Feign 自定义配置(重试、拦截与错误码处理) 实践

    Spring Cloud Feign 自定义配置(重试.拦截与错误码处理) 实践 目录 Spring Cloud Feign 自定义配置(重试.拦截与错误码处理) 实践 引子 FeignClient的 ...

  8. 笔记:Spring Cloud Ribbon 客户端配置详解

    自动化配置 由于 Ribbon 中定义的每一个接口都有多种不同的策略实现,同时这些接口之间又有一定的依赖关系,Spring Cloud Ribbon 中的自动化配置能够很方便的自动化构建接口的具体实现 ...

  9. Spring Cloud Config 分布式配置中心使用教程

    一.简介 在分布式系统中,由于服务数量巨多,为了方便服务配置文件统一管理,实时更新,所以需要分布式配置中心组件.在Spring Cloud中,有分布式配置中心组件spring cloud config ...

随机推荐

  1. 【CCF CSP】 20171203 行车路线 Java(有问题)80分

    问题描述 小明和小芳出去乡村玩,小明负责开车,小芳来导航. 小芳将可能的道路分为大道和小道.大道比较好走,每走1公里小明会增加1的疲劳度.小道不好走,如果连续走小道,小明的疲劳值会快速增加,连续走s公 ...

  2. P4062 [Code+#1]Yazid 的新生舞会

    思路:分治 提交:2次 错因:数组开小 题解: 我们枚举一下众数\(x\). 设\(s[n]=\sum_{i=1}^n [a[i]==x]\) 那么对于区间\((l,r]\),有\(s[r]-s[l] ...

  3. Elasticsearch 调优之 shrink

    对于索引分片数量,我们一般在模板中统一定义,在数据规模比较大的集群中,索引分片数一般也大一些,在我的集群中设置为 24.但是,并不是所有的索引数据量都很大,这些小数据量的索引也同样有较大的分片数.在 ...

  4. CSP-S 2019 D1T2 括号树

    题目链接:[https://www.luogu.com.cn/problem/P5658] 思路: 这道题不难.(为什么我在考场上一点思路也没有??) 假设我们已经处理到树上的节点u(假设1为根节点) ...

  5. 搭建自己的博客(七):使用bootstrap框架美化导航栏

    前面发现自己写css代码以及很多功能太麻烦,故希望在自己的博客中引入bootstrap框架,bootstrap是一个非常强大的前端框架,简单易学容易上手.附上官网地址:bootstrap官网 我使用的 ...

  6. MySQL 5.7:聊聊sql_mode

    1.sql_mode=only_full_group_by 导致的语法错误问题 MySQLSyntaxErrorException Caused by: com.mysql.jdbc.exceptio ...

  7. GO语言反射

    反射可以作为了解,不必深入! 反射介绍 Go语音提供了一种机制在运行时更新变量和检查它们的值.调用它们的方法和它们支持的内在操作,但是在编译时并不知道这些变量的具体类型.这种机制被称为反射.反射也可以 ...

  8. kafka 45个题目介绍

    >1.Kafka面试问答 Apache Kafka的受欢迎程度很高,Kafka拥有充足的就业机会和职业前景.此外,在这个时代拥有kafka知识是一条快速增长的道路.所以,在这篇文章中,我们收集了 ...

  9. TCP和UDP并实现socket的简单通信

    http://www.cnblogs.com/IPrograming/archive/2012/10/15/CSharp_Socket_4.html http://www.cnblogs.com/do ...

  10. git 和conding.net 超详细超简单安装

    在做一下操作前,希望你能知道 1.什么是git? 可以参考https://blog.csdn.net/a909301740/article/details/81636662 如果还想多了解一下还可以参 ...