前言

    伴随着随着微服务概念的不断盛行,与之对应的各种解决方案也层出不穷。这毕竟是一个信息大爆发的时代,各种编程语言大行其道,各有各的优势。但是有一点未曾改变,那就是他们服务的方式,工作的时候各司其职,但是需要提供服务的时候必须要高度统一,这也是微服务的概念之一。日常的工作学习中,我个人更喜欢通用的解决方案,特别是能将不同编程语言亦或者不同编程框架整合到一起的那种,这种解决方案拉近了编程语言之间的距离,让开发者能更清楚的意识到编程语言只是工具,解决问题才是王道。好了口遁到此结束,接下来我就搭建一套.Net体系结合Java体系的项目架构。

概念介绍

接下来我们用到的技术栈名词主要涉及到ASP.NET Core、Nacos、Spring Cloud Gateway,接下来我们分别介绍所使用的的三种框架。

Nacos

Nacos是阿里巴巴开源的致力于服务发现、配置和管理微服务的框架。提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据及流量管理。一般用到的最多的就是当做配置中心和注册中心。

  • 中文官网地址:https://nacos.io/zh-cn/
  • 官方GayHub GitHub地址:https://github.com/alibaba/nacos
  • 下载地址:https://github.com/alibaba/nacos/releases下载运行Nacos之前别忘了安装JDK,如何安装JDK请自行百度这里就不再详细介绍了。下载Nacos方式有两种。第一种是直接下载打包好的文件直接运行。第二种是下载源码自己编译,还需要安装maven,相对于第一个稍微复杂一些,我选择的是第一种方式。

ASP.NET Core

ASP.NET Core是微软开源跨平台的Web开发框架,这个作为.Net开发者相信大家已经非常熟悉了,目前最新的正式版本是3.1.5,也是我们本次搭建框架的重头戏,作为业务的真正执行者

Spring Cloud Gateway

Spring Cloud Gateway为Spring生态系统上的一个API网关组件,主要提供一种简单而有效的方式路由映射到指定的API,并为他们提供安全性、监控和限流等等。最主要的是可以轻松集成已有的Spring各种全家桶,比如咱们这次使用的Nacos,搭建使用起来非常方便。

开始搭建

上面大致介绍了相关概念,相信大家也有了大致的了解。口说无凭,直接开干。

运行Nacos

运行启动Nacos,在浏览器输入输入http://localhost:8848/nacos/#会展示出如下界面。

本次我们主要是用Nacos作为注册中心,所以我们只需要关注服务管理模块即可。

搭建ASP.NET Core项目

    ASP.NET Core项目是我们业务接口的真正提供者,这里我搭建两个项目用于模拟订单系统和商品系统。用Visual Studio新建两个Web空项目,分别是OrderApi和ProductApi。OrderApi调用ProductApi属于内部之间调用,不走Gateway。由于我们使用Nacos作为注册中心,所以我们在需要对接到Nacos上。Nacos有一套Open API的接口对接方式(官方文档)[https://nacos.io/zh-cn/docs/open-api.html]有详细的介绍。自己写终究还是比较麻烦的,好在随着NET Core的日渐成熟,已经有大佬为我们实现了一套sdk基本上满足我们的使用非常的方便,GitHub地址为https://github.com/catcherwong/nacos-sdk-csharp别忘了给大佬个Star,将程序包分别引入OrderApi和ProductApi

<PackageReference Include="nacos-sdk-csharp-unofficial.AspNetCore" Version="0.2.6" />

在appsettings.json中配置,本次展示默认使用的OrderApi作为演示,ProductApi配置方式一致,只需更换注册名称即可

"nacos": {
"ServerAddresses": [ "localhost:8848" ],//Nacos地址
"DefaultTimeOut": 15000,
"Namespace": "",
"ListenInterval": 1000,
"ServiceName": "orderservice" //注册到Nacos上的服务名
}

Startup中配置如下

public void ConfigureServices(IServiceCollection services)
{
//注册Nacos相关服务
services.AddNacosAspNetCore(Configuration); services.AddScoped<NacosDiscoveryDelegatingHandler>();
services.AddHttpClient(ServiceName.ProductService,client=> {
//ServiceName是我为了方便定义的常量类用于承载我们可以使用到的服务名称这里即productservice
client.BaseAddress = new Uri($"http://{ServiceName.ProductService}");
}).AddHttpMessageHandler<NacosDiscoveryDelegatingHandler>(); services.AddControllers();
} public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
//添加Nacos相关中间件
app.UseNacosAspNetCore(); app.UseRouting(); app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}

上面我们提到过,OrderApi调用ProductApi属于内部系统间调用,所以我引入了HttpClientFactory。由于我们使用的是Nacos作为注册中心,所以我写了一个NacosDiscoveryDelegatingHandler配合HttpClientFactory,能更优雅的使用注册中心,如果对这种实现方式不熟悉的话可以参考我之前的博文.NET Core HttpClientFactory+Consul实现服务发现实现原理完全一致,具体代码如下

public class NacosDiscoveryDelegatingHandler: DelegatingHandler
{
private readonly INacosServerManager _serverManager;
private readonly ILogger<NacosDiscoveryDelegatingHandler> _logger; public NacosDiscoveryDelegatingHandler(INacosServerManager serverManager,ILogger<NacosDiscoveryDelegatingHandler> logger)
{
_serverManager = serverManager;
} protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var current = request.RequestUri;
try
{
//通过nacos sdk获取注册中心服务地址,内置了随机负载均衡算法,所以只返回一条信息
var baseUrl = await _serverManager.GetServerAsync(current.Host);
request.RequestUri = new Uri($"{baseUrl}{current.PathAndQuery}");
return await base.SendAsync(request, cancellationToken).ConfigureAwait(false);
}
catch (Exception e)
{
_logger?.LogDebug(e, "Exception during SendAsync()");
throw;
}
finally
{
request.RequestUri = current;
}
}
}

由于我们需要模拟订单接口,所以我新建了OrderController,大致代码如下

[Route("orderapi/[controller]")]
public class OrderController : ControllerBase
{
private List<OrderDto> orderDtos = new List<OrderDto>();
private readonly IHttpClientFactory _clientFactory; public OrderController(IHttpClientFactory clientFactory)
{
orderDtos.Add(new OrderDto { Id = 1,TotalMoney=222,Address="北京市",Addressee="me",From="淘宝",SendAddress="武汉" });
orderDtos.Add(new OrderDto { Id = 2, TotalMoney = 111, Address = "北京市", Addressee = "yi", From = "京东", SendAddress = "北京" });
orderDtos.Add(new OrderDto { Id = 3, TotalMoney = 333, Address = "北京市", Addressee = "yi念之间", From = "天猫", SendAddress = "杭州" }); _clientFactory = clientFactory;
} [HttpGet("get/{id}")]
public OrderDto GetOrder(long id)
{
return orderDtos.FirstOrDefault(i => i.Id == id);
} [HttpGet("getdetails/{id}")]
public async Task<OrderDto> GetOrderDetailsAsync(long id)
{
OrderDto orderDto = GetOrder(id);
if (orderDto != null)
{
OrderDetailDto orderDetailDto = new OrderDetailDto
{
Id = orderDto.Id,
TotalMoney = orderDto.TotalMoney,
Address = orderDto.Address,
Addressee = orderDto.Addressee,
From = orderDto.From,
SendAddress = orderDto.SendAddress
}; //内部调用ProductApi,配合自定义的NacosDiscoveryDelegatingHandler可以更优雅的使用注册中心方式
var client = _clientFactory.CreateClient(ServiceName.ProductService);
var response = await client.GetAsync($"/productapi/product/getall");
var result = await response.Content.ReadAsStringAsync(); orderDetailDto.Products = JsonConvert.DeserializeObject<List<OrderProductDto>>(result);
return orderDetailDto;
}
return orderDto;
}
}

ProductApi提供新建ProductController用于模拟提供商品信息

[Route("productapi/[controller]")]
public class ProductController : ControllerBase
{
private List<ProductDto> productDtos = new List<ProductDto>();
public ProductController()
{
productDtos.Add(new ProductDto { Id = 1,Name="酒精",Price=22.5m });
productDtos.Add(new ProductDto { Id = 2, Name = "84消毒液", Price = 19.9m });
productDtos.Add(new ProductDto { Id = 3, Name = "医用口罩", Price = 55 });
} [HttpGet("get/{id}")]
public ProductDto Get(long id)
{
return productDtos.FirstOrDefault(i => i.Id == id);
} [HttpGet("getall")]
public IEnumerable<ProductDto> GetAll()
{
return productDtos;
}
}

分别启动OrderApi和ProductApi,然后去Nacos上查看,展示如下,说明服务注册成功

我们每个服务只启动了一个实例,每个服务可以启动多个实例,实现高可用和负载均衡。到这里ASP.NET Core相关的代码我们已经搭建完成了,以上只是展示了大致的流程,具体的实现可以去下载Demo查看。

搭建Spring Cloud Gateway

如何搭建Spring Cloud Gateway网上有很多教程,IDEA搭建非常简单,基本上就是起个名字,我们本项目名称就叫apigateway,然后一直点下一步,由于本示例后端的业务系统都是对接到Nacos上的,所以需要在Gateway引入Nacos相关包,在pom.xml引入Nacos

<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>2.2.1.RELEASE</version>
</dependency>

然后再启动类上加上@EnableDiscoveryClient注解

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

在application.yml中添加服务名称和nacos相关配置

server:
#网关启动端口号
port: 8080
spring:
application:
#网关服务名称,也就是注册到Nacos的名称
name: apigateway
#Nacos相关配置
cloud:
nacos:
discovery:
#Nacos服务地址
server-addr: localhost:8848
gateway:
discovery:
locator:
enabled: true
lower-case-service-id: true

启动网关项目apigateway,打开Nacos管理界面,刷新服务列表,如下图所示,说明网关项目注册成功

接下来我们要在网关配置转发相关内容,让apigateway可以转发请求到我们具体的OrderApi和ProductApi。Spring Cloud Gateway默认支持两种配置转发的方式,一种是基于编码的方式,另一种是通过配置的方式。我选用的是基于配置的方式,相对比较灵活一点。在application.yml中添加转发相关配置,如下

server:
port: 8080
spring:
application:
name: apigateway
redis:
host: localhost
port: 6379
database: 0
cloud:
nacos:
discovery:
server-addr: localhost:8848
gateway:
discovery:
locator:
enabled: true
lower-case-service-id: true
#转发相关配置
gateway:
routes:
#唯一标识
- id: productservice
#服务在注册中心的地址
uri: lb://productservice
#转发匹配,即满足/productapi/相关的路径则转发到productservice相关服务
predicates:
- Path=/productapi/**
- id: orderservice
uri: lb://orderservice
predicates:
- Path=/orderapi/**

到这里网关相关的配置差不多先配置这么多,当然网关还需要集成许多核心组件比如限流相关熔断超时相关等等,Spring Cloud Gateway都是可以接入相关组件的比如阿里的Sentinel等等,在这里我们就不做演示了。

测试调用

可以下载本文演示Demo启动Postman进行测试,通过调用网关项目apigateway看看运行效果,首先调用OrderApi接口,OderDetails接口内部调用了ProductApi的接口。如下所示转发成功

然后我们在去调用ProductApi的相关接口,如图所示也是成功的

本文演示Demo下载

总结

    到这里我们的相关示例也就差不多了,能有一套公共的解决方案,使用起来还是非常方便的。这里我只是演示了非常基础的一种模式,就是为了展示技术通用性给我们带来的便利。我个人还是非常喜欢通用的解决方案的,这些方案能让我更关注问题本身,而非某种特定的语言。比如现在容器技术大行其道,我们其实可以忽略原有的许多技术细节,而通过容器平台本身的通用解决方案去解决,在我们使用的时候会非常方便。我也希望更多的开发者,能够关注技术本身或者解决方案本身带给我们的便利,而不是通过有色的眼光去看待这些。能解决的方案终究还是好的方案,它能指导我们的思想,提升我的思维方式,那我们为什么不去接触去学习呢?语言本身固然重要,但是解决问题的思维方式更是不可或缺。废话不多说,本次就到这里,欢迎大家评论区批评指导。

搭建一套ASP.NET Core+Nacos+Spring Cloud Gateway项目的更多相关文章

  1. 使用Spring Cloud Gateway保护反应式微服务(一)

    反应式编程是使你的应用程序更高效的一种越来越流行的方式.响应式应用程序异步调用响应,而不是调用资源并等待响应.这使他们可以释放处理能力,仅在必要时执行处理,并且比其他系统更有效地扩展. Java生态系 ...

  2. 网关我选 Spring Cloud Gateway

    网关可提供请求路由与组合.协议转换.安全认证.服务鉴权.流量控制与日志监控等服务.可选的网关有不少,比如 Nginx.高性能网关 OpenResty.Linkerd 以及 Spring Cloud G ...

  3. Spring Cloud Gateway注册到服务器中心(Consul)

    Spring Cloud Gateway注册到服务器中心(Consul) 准备环境 启动Consul(./consul agent -dev)作为服务中心,默认是8500端口,然后启动spring-c ...

  4. Spring Cloud Gateway+Nacos,yml+properties两种配置文件方式搭建网关服务

    写在前面 网关的作用不在此赘述,举个最常用的例子,我们搭建了微服务,前端调用各服务接口时,由于各服务接口不一样,如果让前端同事分别调用,前端同事会疯的.而网关就可以解决这个问题,网关屏蔽了各业务服务的 ...

  5. Spring Cloud gateway 六 Sentinel nacos存储动态刷新

    微服务当前这么火爆的程度,如果不能学会一种微服务框架技术.怎么能升职加薪,增加简历的筹码?spring cloud 和 Dubbo 需要单独学习.说没有时间?没有精力?要学俩个框架?而Spring C ...

  6. ASP.NET Core WebAPI 开发-新建WebAPI项目

    ASP.NET Core WebAPI 开发-新建WebAPI项目, ASP.NET Core 1.0 RC2 即将发布,我们现在来学习一下 ASP.NET Core WebAPI开发. 网上已经有泄 ...

  7. Nacos整合Spring Cloud Gateway实践

    Spring Cloud Gateway官网:http://spring.io/projects/spring-cloud-gateway Eureka1.0的问题和Nacos对比:https://w ...

  8. ASP.NET Core WebAPI 开发-新建WebAPI项目 转

    转 http://www.cnblogs.com/linezero/p/5497472.html ASP.NET Core WebAPI 开发-新建WebAPI项目   ASP.NET Core We ...

  9. .net core下,Ocelot网关与Spring Cloud Gateway网关的对比测试

    有感于 myzony 发布的 针对 Ocelot 网关的性能测试 ,并且公司下一步也需要对.net和java的应用做一定的整合,于是对Ocelot网关.Spring Cloud Gateway网关做个 ...

随机推荐

  1. Java实现大整数乘法

    1 问题描述 计算两个大整数相乘的结果. 2 解决方案 2.1 蛮力法 package com.liuzhen.chapter5; import java.math.BigInteger; publi ...

  2. Java实现 泊松分酒

    泊松是法国数学家.物理学家和力学家.他一生致力科学事业,成果颇多.有许多著名的公式定理以他的名字命名,比如概率论中著名的泊松分布. 有一次闲暇时,他提出过一个有趣的问题,后称为:"泊松分酒& ...

  3. 一个Jmeter模拟上传文件接口的实例

    资料参考:https://blog.csdn.net/u010390063/article/details/78329373 项目中,避免不了要用到很多上传文件.图片的接口,那么碰到这类接口该如何进行 ...

  4. swagger--Failed to load API definition.

    打开 http://localhost:5000/swagger/v1/swagger.json 提示错误 An unhandled exception occurred while processi ...

  5. C# 反射详解一

    首先反射是基于System.Reflection命名空间下,.Net框架提供的帮助类库,可以读取并使用metadata(元数据:描述对象信息的数据). 我们再来看下代码生成编译的总过程. 编译器编译( ...

  6. 【1】Vim 进阶操作

    一.标签 :tabnew one.c 新建标签[♥] 常用 :tabc 关闭文件   :tabp 切换前一个页面   :tabn 切换下一个页面   gt 普通模式下操作 常用 二.窗口 :sp 水平 ...

  7. cnblogs 博客爬取 + scrapy + 持久化 + 分布式

    目录 普通 scrapy 分布式爬取 cnblogs_spider.py 普通 scrapy # -*- coding: utf-8 -*- import scrapy from ..items im ...

  8. 解决:Error:java: 无效的源发行版: 12

    一. spring cloud项目启动.遇到问题: 二. 解决,共两个地方. 第一个位置: Shift/Ctrl/Alt/S 快捷键一起按 Modules选择你的项目(以及父级项目,如果有的话)-&g ...

  9. Servlet 执行时一般实现哪几个方法?

    public void init(ServletConfig config): public ServletConfig getServletConfig(): public String getSe ...

  10. git环境配置 | GitHub

    注册完GitHub之后,需要配置git,其主要的目的是为了方便文件的上传.下载等. 一. git下载 https://git-scm.com/downloads 在git官网找到相应版本的git下载安 ...