Java基础之《微服务(10)—消息驱动》

一、什么是bus

1、什么是spring cloud bus
spring cloud bus集成了市面上常用的消息代理(rabbit mq、kafka等2种),连接微服务系统中的所有节点,当有数据变更时,可以通过消息代理广播通知微服务及时变更数据。例如微服务的配置更新。

2、bus解决了什么问题
解决了微服务数据变更,及时同步的问题。

二、消息发送模块

1、复制或者新建一个maven模块mycloud-stream-sender

2、pom文件
添加rabbit依赖包spring-cloud-starter-stream-rabbit

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.1.8.RELEASE</version>
		<relativePath /> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>mycloud-stream-sender</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>mycloud-stream-sender</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
		<spring-cloud.version>Greenwich.SR5</spring-cloud.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<!-- 健康监控配置 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-actuator</artifactId>
		</dependency>
		
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
		</dependency>
		
	</dependencies>

	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>${spring-cloud.version}</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

3、发送接口
ISendService.java

package com.example.mycloud.resource;

import org.springframework.cloud.stream.annotation.Output;
import org.springframework.messaging.SubscribableChannel;

/**
 * 发送的接口
 * @author user
 *
 */
public interface ISendService {

	@Output("stream-exchange")
	public SubscribableChannel send();
	
}

4、测试类
TestSender.java

package com.example.mycloud.resource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TestSender {

	@Autowired
	private ISendService sendService;
	
	@RequestMapping("/send")
	public void send() {
		String msg = "abc..........";
		Message message = MessageBuilder.withPayload(msg.getBytes()).build();
		sendService.send().send(message);
	}
}

5、启动类
StreamSenderApplication.java

package com.example.mycloud.run;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.context.annotation.ComponentScan;

import com.example.mycloud.resource.ISendService;

@EnableBinding({ISendService.class}) //把发送接口绑定进来
@EnableDiscoveryClient
@SpringBootApplication
@ComponentScan("com.example.mycloud")
public class StreamSenderApplication {
	
	public static void main(String[] args) {
        SpringApplication.run(StreamSenderApplication.class, args);
    }
}

6、配置文件

spring:
  application:
    name: stream-sender
  rabbitmq:
    host: 127.0.0.1
    port: 5672
    username: admin
    password: admin
    virtual-host: my_vhost
    
server:
  port: 8017

eureka:
  server:
    port: 8010
  instance:
    hostname: localhost
  client:
    registerWithEureka: true
    fetchRegistry: true
    serviceUrl:
      defaultZone: http://admin:123456@${eureka.instance.hostname}:${eureka.server.port}/eureka/

#暴露actuator的所有端口
management:
  endpoints:
    web:
      exposure:
        include: "*"
  endpoint:
    health:
      show-details: ALWAYS
    shutdown:
      #启用shutdown
      enabled: true
      #禁用密码验证
      sensitive: false

三、消息接收模块

1、复制或者新建一个maven模块mycloud-stream-receiver

2、pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.1.8.RELEASE</version>
		<relativePath /> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>mycloud-stream-receiver</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>mycloud-stream-receiver</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
		<spring-cloud.version>Greenwich.SR5</spring-cloud.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<!-- 健康监控配置 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-actuator</artifactId>
		</dependency>
		
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
		</dependency>
		
	</dependencies>

	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>${spring-cloud.version}</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

3、接收接口
IReceiveService.java

package com.example.mycloud.resource;

import org.springframework.cloud.stream.annotation.Input;
import org.springframework.messaging.SubscribableChannel;

/**
 * 接收的接口
 * @author user
 *
 */
public interface IReceiveService {

	@Input("stream-exchange")
	public SubscribableChannel receive();
	
}

4、监听类
ReceiveService.java

package com.example.mycloud.service;

import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.annotation.StreamListener;
import org.springframework.stereotype.Service;

import com.example.mycloud.resource.IReceiveService;

@Service
@EnableBinding(IReceiveService.class) //绑定
public class ReceiveService {

	@StreamListener("stream-exchange")
	public void onReceive(byte[] msg) {
		System.out.println("receive: " + new String(msg));
	}
}

5、启动类
StreamReceiverApplication.java

package com.example.mycloud.run;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.context.annotation.ComponentScan;

@EnableDiscoveryClient
@SpringBootApplication
@ComponentScan("com.example.mycloud")
public class StreamReceiverApplication {
	
	public static void main(String[] args) {
        SpringApplication.run(StreamReceiverApplication.class, args);
    }
}

6、配置文件

spring:
  application:
    name: stream-receiver
  rabbitmq:
    host: 127.0.0.1
    port: 5672
    username: admin
    password: admin
    virtual-host: my_vhost
    
server:
  port: 8018

eureka:
  server:
    port: 8010
  instance:
    hostname: localhost
  client:
    registerWithEureka: true
    fetchRegistry: true
    serviceUrl:
      defaultZone: http://admin:123456@${eureka.instance.hostname}:${eureka.server.port}/eureka/

#暴露actuator的所有端口
management:
  endpoints:
    web:
      exposure:
        include: "*"
  endpoint:
    health:
      show-details: ALWAYS
    shutdown:
      #启用shutdown
      enabled: true
      #禁用密码验证
      sensitive: false

四、stream解决了什么问题

1、应用图

Application Core:应用服务

2、stream解决了开发人员无感知使用消息中间件的问题
因为stream对消息中间件的进一步封装,可以做到代码层面对消息中间件的无感知,甚至于动态的切换中间件(例如从rabbitmq切换为kafka)。使得微服务开发的高度解耦,服务可以关注更多自己的业务流程。

3、middleware
消息中间件,目前只支持rabbitmq和kafka。

4、binder
binder是应用与消息中间件之间的封装。目前实现了kafka和rabbitmq的binder。通过binder,可以很方便的连接中间件,可以动态改变消息类型。

5、@Input
注解标识输入通道,通过该输入通道接收到的消息进入应用程序。

6、@Output
注解标识输出通道,发布的消息将通过该通道离开应用程序。

7、@StreamListener
监听队列,用于消费者的队列的消息接收。

8、@EnableBinding
指信道channel和exchange绑定在一起。

五、消息的分组

1、之前的服务有什么问题
(1)队列是临时队列
(2)如果起多个receiver就会有多个队列queue绑定到exchange上,多个服务会同时接收到消息,消费多次

2、指定信道绑定交换器,交换器绑定队列
stream-sender模块
ISendService.java添加:

package com.example.mycloud.resource;

import org.springframework.cloud.stream.annotation.Output;
import org.springframework.messaging.SubscribableChannel;

/**
 * 发送的接口
 * @author user
 *
 */
public interface ISendService {

	@Output("stream-exchange")
	public SubscribableChannel send();
	
	//消息分组
	String OUTPUT = "groupOutput";
	
	@Output(ISendService.OUTPUT)
	public SubscribableChannel send2();
	
}

TestSender.java添加:

package com.example.mycloud.resource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.example.mycloud.bean.Product;

@RestController
public class TestSender {

	@Autowired
	private ISendService sendService;
	
	@RequestMapping("/send")
	public void send() {
		String msg = "abc..........";
		Message message = MessageBuilder.withPayload(msg.getBytes()).build();
		sendService.send().send(message);
	}
	
	//消息分组
	@RequestMapping("/send2")
	public void send2() {
		Product product = new Product();
		product.setId("1");
		product.setName("abc");
		Message message = MessageBuilder.withPayload(product).build();
		sendService.send().send(message);
	}
}

配置文件添加:

spring:
  cloud:
    stream:
      bindings:
        groupOutput:
          #指定输出通道对应的exchange主题名
          destination: object-exchange

stream-receiver模块
IReceiveService.java添加:

package com.example.mycloud.resource;

import org.springframework.cloud.stream.annotation.Input;
import org.springframework.messaging.SubscribableChannel;

/**
 * 接收的接口
 * @author user
 *
 */
public interface IReceiveService {

	@Input("stream-exchange")
	public SubscribableChannel receive();
	
	//消息分组
	String INPUT = "groupInput";
	
	@Input(IReceiveService.INPUT)
	public SubscribableChannel receive2();
}

ReceiveService.java添加:

package com.example.mycloud.service;

import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.annotation.StreamListener;
import org.springframework.stereotype.Service;

import com.example.mycloud.bean.Product;
import com.example.mycloud.resource.IReceiveService;

@Service
@EnableBinding(IReceiveService.class) //绑定
public class ReceiveService {

	@StreamListener("stream-exchange")
	public void onReceive(byte[] msg) {
		System.out.println("receive: " + new String(msg));
	}
	
	//消息分组
	@StreamListener(IReceiveService.INPUT)
	public void onReceive2(Product obj) {
		System.out.println("receive: " + obj.toString());
	}
}

配置文件添加:

spring:
  cloud:
    stream:
      bindings:
        groupInput:
          #指定输入通道对应的exchange主题名
          destination: object-exchange
          #具体分组对应MQ的队列名称,并持久化队列
          group: groupQueue

3、查看绑定情况

消息分组解决了,队列持久化问题。还有集群中一个队列对应多个consumer,只消费一次。

六、消息的分区
集群环境下,多个服务组成一个集群,如果想让相同的消息被同一个服务消费

1、stream-receiver模块,修改配置文件

spring:
  cloud:
    stream:
      bindings:
        partInput:
          consumer:
            #开启消费者分区功能
            partitioned: true
      #指定了当前消费者的总示例数量
      instanceCount: 2
      #设置当前实例的索引号,从0开始
      instanceIndex: 0

2、stream-sender模块,修改配置文件

spring:
  cloud:
    stream:
      bindings:
        partOutput:
          producer:
            #通过该参数指定了分区键的表达式规则
            partitionKeyExpression: payload
            #指定了消息分区的数量
            partitionCount: 2

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java微服务是一种基于微服务架构的应用开发模式,它将一个大型的应用系统拆分成多个小型的、独立部署的服务单元,每个服务单元都可以独立开发、部署和扩展。Java微服务的发展趋势主要包括以下几个方面: 1. 云原生:随着云计算的普及,Java微服务也越来越多地应用于云原生环境中。云原生是一种基于容器化和轻量级编排的应用开发模式,它可以提供更高的弹性和可伸缩性,使得Java微服务更加适应云环境的需求。 2. 无服务架构:无服务架构是一种将应用逻辑以函数的形式进行部署和执行的架构模式。Java微服务可以通过使用无服务框架(如AWS Lambda、Azure Functions等)来实现更细粒度的服务拆分和部署,从而提高开发效率和资源利用率。 3. 容器化:容器化是将应用程序及其依赖项打包到一个独立的、可移植的容器中,并在任何环境中运行的技术。Java微服务可以使用容器技术(如Docker、Kubernetes等)来实现快速部署、弹性伸缩和服务治理等功能。 4. 事件驱动架构:事件驱动架构是一种基于事件和消息的系统设计模式,它可以实现松耦合、异步处理和可扩展性。Java微服务可以使用事件驱动架构(如Apache Kafka、RabbitMQ等)来实现服务之间的解耦和异步通信。 5. AI和机器学习:随着人工智能和机器学习的快速发展,Java微服务也开始与这些技术进行结合。Java微服务可以使用机器学习模型来实现智能推荐、数据分析等功能,从而提供更加智能化的服务。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值