• 电商秒杀系统:电商微服务框架组件


    为什么需要框架组件

    可以对比参考ABP框架中的微服务示例的通讯,abp的微服务示例是使用“异步消息通信”方式。与cp的微服务对比理解下

    就是为了方便,把重复的代码都封装好。 

    参考

    Abp Vnext2.0核心组件源码解析与简单应用

    abp官网文档:微服务解决方案示例

     

    组件所在位置:Framework=》Cores

     

    组件和服务的调用关系

    中台调用组件(Middleware) ,没调用

    注册中心组件(Registry),没调用

    断路器Polly组件(Pollys),没调用

    框架异常组件(Exceptions),没调用

    负载均衡组件(Cluster) ,调用了

    • 注册中心组件(Registry)

    动态中台调用组件(DynamicMiddleware) ,调用了

    • 中台调用组件(Middleware) 
    • 注册中心组件(Registry)
    • 负载均衡组件(Cluster)

    微服务客户端组件(MicroClients),调用了

    • 动态中台调用组件(DynamicMiddleware)
    • 断路器Polly组件(Pollys)

    ----------------------------------上面的是组件调用组件,下面的是服务调用组件----------------------------------

    都是在Startup中使用组件

    SeckillAggregateServices(秒杀聚合服务),Startup 调用了

    • 微服务客户端组件(MicroClients)
      • 使用了该组件的AddMicroClient方法来添加微服务客户端,该方法内实现了以下功能
        • 注册AddMiddleware
        • 注册客户端工厂
        • 注册客户端集合
        • 注册代理对象
                services.AddMicroClient(options =>
                {
                    //程序集名称
                    options.AssmelyName = "RuanMou.Projects.SeckillAggregateServices";
                    //动态中台选项
                    options.dynamicMiddlewareOptions = mo =>
                    {
                        //服务发现选项
                        mo.serviceDiscoveryOptions = sdo =>
                        //服务发现地址
                        { sdo.DiscoveryAddress = "http://localhost:8500"; };
                    };
                });

    OrderServices(订单服务)、PaymentServices(支付服务)、ProductServices(商品服务)、SeckillServices(秒杀服务)、UserServices(用户服务),Startup 调用了

    • 注册中心组件(Registry)
      • 使用了该组件的AddServiceRegistry方法来服务注册,该方法内实现了以下功能
        • 配置选项到 IOC
        • 注册consul注册
        • 注册开机自动注册服务

    下面是OrderServices(订单服务)使用注册中心组件示例:

                services.AddServiceRegistry(options =>
                {
                    options.ServiceId = Guid.NewGuid().ToString(); //服务ID
                    options.ServiceName = "OrderServices"; //服务名称
                    options.ServiceAddress = "https://localhost:5002"; //服务地址
                    options.HealthCheckAddress = "/HealthCheck"; //服务健康检查地址
                    options.RegistryAddress = "http://localhost:8500"; //服务注册地址
                });

    中台调用组件(Middleware)

    如果要扩展为grpc框架通讯,只要创建一个另外一个类,实现IMiddleService接口的方法就好 

    中台结果:MiddleResult

    JsonConvert.DeserializeObject:将JSON反序列化为指定的.NET类型

    变量:

    ErrorNo:0是成功,其他都是失败

    ErrorInfo:失败信息

    属性:
    resultDic:用于非结果集返回

    resultList:用于结果集返回

    Result:返回动态结果(通用)

    方法:

    //把Json格式的字符串反序列化为MiddleResult

    public static MiddleResult JsonToMiddleResult(string jsonStr)

    构造函数:

    //将JSON反序列化为指定的.NET类型

    public MiddleResult(string jsonStr)

    using Newtonsoft.Json;
    using System.Collections.Generic;
    
    namespace RuanMou.Projects.Cores.Middleware
    {
        /// <summary>
        /// 中台结果:
        /// 变量:
        /// SUCCESS:?
        /// ErrorNo:0是成功,其他都是失败
        /// ErrorInfo:失败信息
        /// 
        /// 属性:
        /// resultDic:用于非结果集返回
        /// resultList:用于结果集返回
        /// Result:返回动态结果(通用)
        /// 
        /// 方法:
        /// JsonToMiddleResult:把Json格式的字符串反序列化为MiddleResult
        /// 
        /// 构造函数:根据传入的参数更新上面的变量和属性,都没有用到?需要调式确认
        /// 
        /// </summary>
        public class MiddleResult
        {
            public const string SUCCESS = "0"; //没有被用过?调式看看
            /// <summary>
            /// 是否成功状态:0是成功,其他都是失败
            /// </summary>
            public string ErrorNo { set; get; } 
            /// <summary>
            /// 失败信息
            /// </summary>
            public string ErrorInfo { set; get; }
            /// <summary>
            /// 用于非结果集返回
            /// </summary>
            public IDictionary<string, object> resultDic { set; get; }
            /// <summary>
            /// 用于结果集返回
            /// </summary>
            public IList<IDictionary<string, object>> resultList { set; get; }
            /// <summary>
            /// 返回动态结果(通用),使用动态解释数据类型dynamic
            /// </summary>
            public dynamic Result { set; get; }
    
            /// <summary>
            /// 构造函数():无参,
            /// resultDic(用于非结果集返回)=字典,
            /// resultList(用于结果集返回)=集合<字典>
            /// </summary>
            public MiddleResult()
            {
                resultDic = new Dictionary<string, object>();
                resultList = new List<IDictionary<string, object>>();
            }
    
            /// <summary>
            /// 构造函数(string):把Json格式的字符串反序列化为MiddleResult
            /// </summary>
            /// <param name="jsonStr"></param>
            public MiddleResult(string jsonStr)
            {
                MiddleResult result = JsonConvert.DeserializeObject<MiddleResult>(jsonStr);
            }
            /// <summary>
            /// 把Json格式的字符串反序列化为MiddleResult
            /// JsonConvert.DeserializeObject:将JSON反序列化为指定的.NET类型
            /// </summary>
            /// <param name="jsonStr"></param>
            /// <returns></returns>
            public static MiddleResult JsonToMiddleResult(string jsonStr)
            {
                MiddleResult result = JsonConvert.DeserializeObject<MiddleResult>(jsonStr);
                return result;
            }
    
            /// <summary>
            /// 构造函数:
            /// </summary>
            /// <param name="errorNo"></param>
            /// <param name="errorInfo"></param>
            public MiddleResult(string errorNo, string errorInfo)
            {
                this.ErrorNo = errorNo;
                this.ErrorInfo = errorInfo;
                resultDic = new Dictionary<string, object>();
                resultList = new List<IDictionary<string, object>>();
            }
            //构造函数,引用上面2个参数的构造函数?
            public MiddleResult(string errorNo, string erroInfo, IDictionary<string, object> resultDic, IList<IDictionary<string, object>> resultList) : this(errorNo, erroInfo)
            {
                this.resultDic = resultDic;
                this.resultList = resultList;
                this.resultDic = resultDic;
                this.resultList = resultList;
            }
        }
    }
    View Code

    中台服务接口:IMiddleService

    用MiddleResult类声明的方法名,如下

    • Get:获取/查询
    • Post:创建/新增
    • Delete:删除
    • Put:更新/修改
    • PostDynamic:post请求动态参数
    • PutDynamic:put请求动态参数

    Http中台请求结果:HttpMiddleService(重点)

    IHttpClientFactory:组件的工厂抽象,该组件可使用自定义配置为给定逻辑名称创建 HttpClient 实例

    IHttpClientFactory.CreateClient(String):使用与 name 指定的逻辑名称相对应的配置来创建和配置 HttpClient 实例。

    HttpClient:提供基本类,用于发送 HTTP 请求和接收来自通过 URI 确认的资源的 HTTP 响应。

    HttpClient.PostAsync(string requestUri, HttpContent content):以异步操作将 POST 请求发送给指定 URI。

    HttpContent:表示 HTTP 实体正文和内容标头的基类。

    StringContent(String, Encoding, String):创建 System.Net.Http.StringContent 类的新实例

    HttpResponseMessage:表示包括状态代码和数据的 HTTP 响应消息。

    在 ASP.NET Core 中使用 IHttpClientFactory 发出 HTTP 请求

    JsonConvert.SerializeObject:将指定的对象序列化为JSON字符串

    核心的4行代码

    复制代码
    private readonly IHttpClientFactory httpClientFactory;
    //
    HttpClient httpClient = httpClientFactory.CreateClient(String); 
    //
    HttpContent hc = new StringContent(String, Encoding, String); 
    //
    HttpResponseMessage response = await httpClient.PostAsync(string requestUri, HttpContent content);
    复制代码

    另外添加的方法:

    • 将HttpResponseMessage转换成MiddleResult类的Json格式
      • private MiddleResult GetMiddleResult(HttpResponseMessage httpResponseMessage)

    实现接口IMiddleService的全部方法 :这些方法返回的都是上面的MiddleResult方法,返回Json格式

    • Get:获取/查询
      • public MiddleResult Get(string middleUrl, IDictionary<string, object> middleParam)
    • Post:创建/新增
      • public MiddleResult Post(string middleUrl, IDictionary<string, object> middleParam)
      • public MiddleResult Post(string middleUrl, IList<IDictionary<string, object>> middleParams)
    • Delete:删除
      • public MiddleResult Delete(string middleUrl, IDictionary<string, object> middleParam)
    • Put:更新/修改
      • public MiddleResult Put(string middleUrl, IDictionary<string, object> middleParam)
      • public MiddleResult Put(string middleUrl, IList<IDictionary<string, object>> middleParams)
    • PostDynamic:post请求动态参数
      • public MiddleResult PostDynamic(string middleUrl, dynamic middleParam)
    • PutDynamic:put请求动态参数
      • public MiddleResult PutDynamic(string middleUrl, dynamic middleParam)
    using Newtonsoft.Json;
    using RuanMou.Projects.Commons.Exceptions;
    using RuanMou.Projects.Cores.Middleware.transports;
    using RuanMou.Projects.Cores.Utils;
    using System.Collections.Generic;
    using System.Net;
    using System.Net.Http;
    using System.Text;
    
    namespace RuanMou.Projects.Cores.Middleware.support
    {
        /// <summary>
        /// Http中台请求结果:
        /// 实现接口IMiddleService的全部方法
        /// HttpClient:提供用于发送 HTTP 请求并从 URI 标识的资源接收 HTTP 响应的基类
        ///     .GetAsync、.PostAsync、.PutAsync、.DeleteAsync:以异步操作将这几种请求发送给指定URI
        ///         .Result:获取此 System.Threading.Tasks.Task`1 的结果值
        /// IHttpClientFactory:组件的工厂抽象,该组件可使用自定义配置为给定逻辑名称创建 HttpClient 实例
        /// IHttpClientFactory.CreateClient:使用与 name 指定的逻辑名称相对应的配置来创建和配置 HttpClient 实例。
        /// HttpResponseMessage:表示包括状态代码和数据的 HTTP 响应消息
        /// HttpContent:表示 HTTP 实体正文和内容标头的基类
        /// JsonConvert.SerializeObject:将指定的对象序列化为JSON字符串。
        /// </summary>
        public class HttpMiddleService : IMiddleService
        {
            private IHttpClientFactory httpClientFactory;
            private const string HttpConst = "mrico";
    
            public HttpMiddleService(IHttpClientFactory httpClientFactory)
            {
                this.httpClientFactory = httpClientFactory;
            }
    
            public MiddleResult Delete(string middleUrl, IDictionary<string, object> middleParam)
            {
                // 1、获取httpClient
                HttpClient httpClient = httpClientFactory.CreateClient(HttpConst);
    
                // 2、Delete请求                                    以异步操作将 DELETE 请求发送给指定 URI。
                HttpResponseMessage httpResponseMessage = httpClient.DeleteAsync(middleUrl).Result;
    
                return GetMiddleResult(httpResponseMessage);
            }
    
    
            public MiddleResult Get(string middleUrl, IDictionary<string, object> middleParam)
            {
                // 1、获取httpClient
                HttpClient httpClient = httpClientFactory.CreateClient(HttpConst);
    
                // 2、参数转换为url方式
                string urlParam = HttpParamUtil.DicToHttpUrlParam(middleParam);
    
                // 3、Get请求                                        
                HttpResponseMessage httpResponseMessage = httpClient.GetAsync(middleUrl + urlParam).Result;
    
                return GetMiddleResult(httpResponseMessage);
            }
    
            public MiddleResult Post(string middleUrl, IDictionary<string, object> middleParam)
            {
                // 1、获取httpClient
                HttpClient httpClient = httpClientFactory.CreateClient(HttpConst);
    
                // 2、转换成json参数
                HttpContent httpContent = new StringContent(JsonConvert.SerializeObject(middleParam), Encoding.UTF8, "application/json");
    
                // 3、Post请求
                HttpResponseMessage httpResponseMessage = httpClient.PostAsync(middleUrl, httpContent).Result;
    
                return GetMiddleResult(httpResponseMessage);
            }
    
            public MiddleResult Post(string middleUrl, IList<IDictionary<string, object>> middleParams)
            {
                // 1、获取httpClient
                HttpClient httpClient = httpClientFactory.CreateClient(HttpConst);
    
                // 2、转换成json参数
                HttpContent httpContent = new StringContent(JsonConvert.SerializeObject(middleParams), Encoding.UTF8, "application/json");
    
                // 3、Post请求
                HttpResponseMessage httpResponseMessage = httpClient.PostAsync(middleUrl, httpContent).Result;
    
                return GetMiddleResult(httpResponseMessage);
            }
    
            public MiddleResult PostDynamic(string middleUrl, dynamic middleParam)
            {
                // 1、获取httpClient
                HttpClient httpClient = httpClientFactory.CreateClient(HttpConst);
    
                // 2、转换成json参数
                HttpContent httpContent = new StringContent(JsonConvert.SerializeObject(middleParam), Encoding.UTF8, "application/json");
    
                // 3、Post请求
                HttpResponseMessage httpResponseMessage = httpClient.PostAsync(middleUrl, httpContent).Result;
    
                return GetMiddleResult(httpResponseMessage);
            }
    
            public MiddleResult Put(string middleUrl, IDictionary<string, object> middleParam)
            {
                // 1、获取httpClient
                HttpClient httpClient = httpClientFactory.CreateClient(HttpConst);
    
                // 2、转换成json参数
                HttpContent httpContent = new StringContent(JsonConvert.SerializeObject(middleParam), Encoding.UTF8, "application/json");
                // 3、Put请求
                HttpResponseMessage httpResponseMessage = httpClient.PutAsync(middleUrl, httpContent).Result;
    
                return GetMiddleResult(httpResponseMessage);
            }
    
            public MiddleResult Put(string middleUrl, IList<IDictionary<string, object>> middleParams)
            {
                // 1、获取httpClient
                HttpClient httpClient = httpClientFactory.CreateClient(HttpConst);
    
                // 2、转换成json参数
                HttpContent httpContent = new StringContent(JsonConvert.SerializeObject(middleParams), Encoding.UTF8, "application/json");
    
                // 3、Put请求
                HttpResponseMessage httpResponseMessage = httpClient.PutAsync(middleUrl, httpContent).Result;
    
                return GetMiddleResult(httpResponseMessage);
            }
    
    
            public MiddleResult PutDynamic(string middleUrl, dynamic middleParam)
            {
                // 1、获取httpClient
                HttpClient httpClient = httpClientFactory.CreateClient(HttpConst);
    
                // 2、转换成json参数
                HttpContent httpContent = new StringContent(JsonConvert.SerializeObject(middleParam), Encoding.UTF8, "application/json");
                // 3、Put请求
                HttpResponseMessage httpResponseMessage = httpClient.PutAsync(middleUrl, httpContent).Result;
    
                return GetMiddleResult(httpResponseMessage);
            }
            /// <summary>
            /// 将HttpResponseMessage转换成MiddleResult类的Json格式
            /// </summary>
            /// <param name="httpResponseMessage"></param>
            /// <returns></returns>
            private MiddleResult GetMiddleResult(HttpResponseMessage httpResponseMessage)
            {
                // 3、将HttpResponseMessage转换成MiddleResult
                if (httpResponseMessage.StatusCode.Equals(HttpStatusCode.OK)
                    || httpResponseMessage.StatusCode.Equals(HttpStatusCode.Created) ||
                    httpResponseMessage.StatusCode.Equals(HttpStatusCode.Accepted))
                {
                    string httpJsonString = httpResponseMessage.Content.ReadAsStringAsync().Result;
    
                    // 3.1 创建MiddleResult
                    return MiddleResult.JsonToMiddleResult(httpJsonString);
                }
                else
                {
                    throw new FrameException($"{HttpConst}服务调用错误:{httpResponseMessage.Content.ReadAsStringAsync().ToString()}");
                }
            }
        }
    }
    View Code 

    中台配置选项:MiddlewareOptions

    两个属性:polly熔断降级选项、客户端名称

    • public Action<PollyHttpClientOptions> pollyHttpClientOptions { get; }
    • public string HttpClientName { set; get; }
    View Code

    中台ServiceCollection扩展方法:MiddlewareServiceCollectionExtensions

    使用上面的MiddlewareOptions类

    添加中台

    • 使用中台配置选项MiddlewareOptions
    • 使用自定义的Polly熔断组件
    • 注册中台组件:中台组件的接口与实现类注入
    using Microsoft.Extensions.DependencyInjection;
    using RuanMou.Projects.Cores.Cluster.Extentions;
    using RuanMou.Projects.Cores.HttpClientPolly;
    using RuanMou.Projects.Cores.Middleware.options;
    using RuanMou.Projects.Cores.Middleware.support;
    using RuanMou.Projects.Cores.Middleware.transports;
    using RuanMou.Projects.Cores.Middleware.Urls;
    using RuanMou.Projects.Cores.Middleware.Urls.consul;
    using RuanMou.Projects.Cores.Registry.Extentions;
    using System;
    
    namespace RuanMou.Projects.Cores.Middleware.Extentions
    {
        /// <summary>
        ///  中台组件的ServiceCollection扩展方法:以便在Startup类的ConfigureServices方法可以使用此组件
        /// </summary>
        public static class MiddlewareServiceCollectionExtensions
        {
            /// <summary>
            /// 添加中台
            /// </summary>
            /// <typeparam name="IMiddleService"></typeparam>
            /// <param name="services"></param>
            /// <returns></returns>
            public static IServiceCollection AddMiddleware(this IServiceCollection services)
            {
                AddMiddleware(services, options => {});
                return services;
            }
    
            /// <summary>
            /// 添加中台:
            /// 1 使用中台配置选项MiddlewareOptions
            /// 2 使用自定义的Polly熔断组件
            /// 3 注册中台组件:中台组件的接口与实现类注入
            /// </summary>
            /// <typeparam name="IMiddleService"></typeparam>
            /// <param name="services"></param>
            /// <returns></returns>
            public static IServiceCollection AddMiddleware(this IServiceCollection services, Action<MiddlewareOptions> options)
            {
                MiddlewareOptions middlewareOptions = new MiddlewareOptions();
                options(middlewareOptions);
    
                // 1、注册到IOC
                services.Configure<MiddlewareOptions>(options);
    
                // 2、添加HttpClient,使用自定义的Polly熔断组件
                // services.AddHttpClient(middlewareOptions.HttpClientName);
                services.AddPollyHttpClient(middlewareOptions.HttpClientName, middlewareOptions.pollyHttpClientOptions);
    
                // 3、注册中台组件:中台组件的接口与实现类注入
                //AddSingleton:将TService 中指定类型的单一实例服务和 TImplementation中指定类型的实现添加到指定的IServiceCollection 中。
                services.AddSingleton<IMiddleService, HttpMiddleService>();
    
                return services;
            }
        }
    }
    View Code

    断路器Polly组件封装(Pollys)

    注册中心组件封装(Registry)

    负载均衡组件封装(Cluster)

    动态中台调用组件封装(DynamicMiddleware)

    微服务客户端组件封装(MicroClients)

    框架异常组件封装(Exceptions)

     

  • 相关阅读:
    bzoj 1257: [CQOI2007]余数之和sum 数论
    codevs 1063 合并果子 STL 优先队列
    HTTP错误code大全
    URL中的特殊字符处理笔记
    单例中懒汉和饿汉的本质区别
    关于静态方法的使用方式
    111
    WebService 简单安全验证
    WebService安全解决方案—简单握手协议
    RESTEasy使用json返回的例子
  • 原文地址:https://www.cnblogs.com/qingyunye/p/13627728.html
Copyright © 2020-2023  润新知