Spring Cloud实战7——采用Spring Cloud Stream的事件驱动架构

1. 消息传递,EDA和微服务的案例

使用同步请求 - 响应方法来通信状态更改

这种方法存在三个问题:

  • 服务之间的紧密联系
  • 服务之间的脆弱性
  • 不愿意增加新的消费者以改变Organization service

使用消息传递在服务之间传递状态更改

这种方法有四个好处:

  • 松耦合
  • 耐久力
  • 可扩展性
  • 灵活性

消息传递架构的缺点

基于消息的架构可能很复杂,需要开发团队密切关注几个关键事项,包括:

  • 消息处理语义
  • 消息可见性
  • 消息编排

2. 介绍Spring Cloud Stream

Spring Cloud Stream架构

如何使用Spring Cloud Stream来促进此消息传递

通过在Spring Cloud中发布和使用消息,发布和使用消息涉及四个组件:Source、Channel、Binder和Sink。

3. 编写简单的消息生产者和消费者

在organization service中编写消息生成器

添加依赖

<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-stream</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>

启动类添加注释,@EnableBinding注释告诉Spring Cloud Stream希望将服务绑定到消息代理

@SpringBootApplication
@EnableBinding(Source.class)
public class OrganizationserviceApplication {
	@Primary
	@LoadBalanced
	@Bean
	public RestTemplate restTemplate() {
		RestTemplate template = new RestTemplate();
		List interceptors = template.getInterceptors();
		if (interceptors == null) {
			template.setInterceptors(Collections.singletonList(new UserContextInterceptor()));
		} else {
			interceptors.add(new UserContextInterceptor());
			template.setInterceptors(interceptors);
		}
		return template;
	}
	public static void main(String[] args) {
		SpringApplication.run(OrganizationserviceApplication.class, args);
	}
}

将消息发布到消息代理

@Component
@AllArgsConstructor
public class SimpleSourceBean {
    private Source source;

    private static final Logger logger = LoggerFactory.getLogger(SimpleSourceBean.class);

    public void publishOrgChange(String action, Long orgId) {
        logger.debug("Sending RabbitMQ message {} for Organization Id: {}", action, orgId);
        OrganizationChangeModel changeModel = new OrganizationChangeModel(OrganizationChangeModel.class.getTypeName(),
                action, orgId, UserContext.getCorrelationId());
        source.output().send(MessageBuilder.withPayload(changeModel).build());
    }
}

用于发布消息的Spring Cloud Stream配置

spring:
	cloud:
		stream:
			bindings:
			output:
				destination: orgChangeTopic
				content-type: application/json

在organization service中发布消息

@Service
@AllArgsConstructor
public class OrganizationServiceImpl implements OrganizationService{
	private OrganizationRepository organizationRepository;
	private SimpleSourceBean simpleSourceBean;
	@Override
	@HystrixCommand
	public void saveOrganizations(Organization organization) {
		organizationRepository.save(organization);
		simpleSourceBean.publishOrgChange("SAVE", organization.getId());
	}
}

在licensing service中编写消息使用者

和organization service一样添加相同的依赖

<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-stream</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>

使用Spring Cloud Stream消费消息

@EnableBinding(Sink.class)
@AllArgsConstructor
public class OrganizationChangeHandler {

    private static final Logger logger = LoggerFactory.getLogger(OrganizationChangeHandler.class);

    @StreamListener(Sink.INPUT)
    @CacheEvict(value = "organizations", key = "#orgChange.organizationId", condition = "#orgChange.action == 'UPDATE' or #orgChange.action == 'DELETE'")
    public void loggerSink(OrganizationChangeModel orgChange) {
        logger.debug("Received a message of type " + orgChange.getType());
        switch(orgChange.getAction()){
            case "GET":
                logger.debug("Received a GET event from the organization service for organization id {}", orgChange.getOrganizationId());
                break;
            case "SAVE":
                logger.debug("Received a SAVE event from the organization service for organization id {}", orgChange.getOrganizationId());
                break;
            case "UPDATE":
                logger.debug("Received a UPDATE event from the organization service for organization id {}", orgChange.getOrganizationId());
                break;
            case "DELETE":
                logger.debug("Received a DELETE event from the organization service for organization id {}", orgChange.getOrganizationId());
                break;
            default:
                logger.error("Received an UNKNOWN event from the organization service of type {}", orgChange.getType());
                break;

        }
    }
}

将licensing service映射到rabbitmq中的消息主题

spring:
	cloud:
		stream:
			bindings:
			input:
				destination: orgChangeTopic
				content-type: application/json
				group: licensingGroup

使用者组保证消息仅由一组服务实例处理一次

4. Spring Cloud Stream用例:分布式缓存

使用Redis缓存查找

添加Spring Redis依赖

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-cache</artifactId>
</dependency>

OrganizationServiceClient中定义使用Redis缓存的方法

@FeignClient("organizationservice")
public interface OrganizationServiceClient {
    @Cacheable(value = "organizations", cacheManager = "orgProtoCacheManager")
    @RequestMapping(method = RequestMethod.GET, value = "/v1/organizations/{organizationId}", consumes = "application/x-protobuf", produces = "application/x-protobuf")
    OrganizationProto.Organization getOrganizationProtobuf(@PathVariable("organizationId") Long organizationId);
}

转载于:https://my.oschina.net/u/869718/blog/2250372

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值