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

配置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. python实现字符串中如果遇到连续重复的字符只出现一次非去重

    需求:在一个字符串中, 如果遇到连续重复的字符只出现一个,(不是去重) 例:str1 = 'aabbccddaabbccdd' 输出结果为:‘abcdabcd’ 具体实现代码如下: def func( ...

  2. HDU 6162 - Ch’s gift | 2017 ZJUT Multi-University Training 9

    /* HDU 6162 - Ch’s gift [ LCA,线段树 ] | 2017 ZJUT Multi-University Training 9 题意: N节点的树,Q组询问 每次询问s,t两节 ...

  3. [TJOI2015]弦论(第k小子串)

    题意: 对于一个给定的长度为n的字符串,求出它的第k小子串. 有参数t,t为0则表示不同位置的相同子串算作一个,t为1则表示不同位置的相同子串算作多个. 题解: 首先,因为t的原因,后缀数组较难实现, ...

  4. 普通页面引入React(使用和不使用JSX)

    1. 不使用JSX 优点: 不用配置有关JSX的编译. 依赖语法: React.createElement(component/type, props, ...chilidren); //第一个参数可 ...

  5. 后台(一)vue+element-ui(全局配置)

    vue init webpack    项目名称 npm install axios                    //先安装! npm install --save axios vue-ax ...

  6. ZOJ2314 Reactor Cooling(无源汇上下界可行流)

    The terrorist group leaded by a well known international terrorist Ben Bladen is buliding a nuclear ...

  7. epoll反应堆模型代码

    libevent函数库核心思想 /*** epoll_loop.c ***/ #include<stdio.h> #include<sys/epoll.h> #include& ...

  8. 1825:【01NOIP提高组】数的划分

    #include<bits/stdc++.h> using namespace std; ],tot; void dfs(int num,int pos) { if(pos==k) ]) ...

  9. Tkinter 之主窗口参数

    一.常用参数 语法 作用 window= tk.TK() 创建窗口 window['height'] = 300 设置高 window['width'] = 500 设置宽 window.title( ...

  10. excel被保护或者锁定时候按住alt和enter可以输入换行

    excel被保护或者锁定时候按住alt和enter可以输入换行