/// <summary> /// 初始化 /// </summary> internal Endpoint(Configuration configuration) { this.Configuration = configuration; if (this.Configuration.ID == null) { this.Configuration.Identity(new Identity() { Source = System.Environment.MachineName, //TODO:修改为外部指定 AuthKey = System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(System.Environment.MachineName, "MD5") }); } this._localTable = new List <ServiceConfig>(); this._clientTable = new List <ServiceConfig>(); this._associateTable = new ServiceConfigTable(); }
//刷新容器 private void RefreshContainer(ServiceConfigTable associateTable) { //排除从关联节点获取到的本地服务 associateTable.Services = (associateTable ?? new ServiceConfigTable()).Services.Where(o => //由于存在多地址情况 只判断Name+AssemblyName是否相同即可,避免本地暴露的服务被指向其他地址 !this._localTable.Exists(p => p.Name.Equals(o.Name) && p.AssemblyName.Equals(o.AssemblyName))).ToArray(); //卸载原有而新服务表中不存在的远程服务 this._container.ClearRemoteServices(this.FilterANotInB(this._associateTable, associateTable)); //替换关联节点服务表 先于容器注册前替换避免此时的调用拿到组件而没有服务信息 this._associateTable = associateTable; //清空配置表 this.ClearServiceTable(); //注册原来没有而新服务表中存在的远程服务 //this._container.RegisterRemoteServices(this.FilterANotInB(associateTable, this._associateTable)); //重新注册避免外部原因导致的远程组件移除 this._container.RegisterRemoteServices(associateTable.Services.Select(o => o.Type).ToArray()); }
//准备服务表 private void PrepareServiceTable(ServiceConfigTable table, List <ServiceConfig> configs) { //填充services用于负载均衡支持 configs.ForEach(o => { //保留configs属性为了短期兼容原不支持多地址的设计 table.AddServiceConfig(o); var service = table.Services .ToList() .FirstOrDefault(p => p.Name.Equals(o.Name) && p.AssemblyName.Equals(o.AssemblyName)); if (service == null) { service = new ServiceInfo(o.Name, o.AssemblyName); table.AddServiceInfo(service); } service.LoadBalancingAlgorithm = o.LoadBalancingAlgorithm; service.AddServiceConfig(o); }); }
//清空服务表 private void ClearServiceTable() { lock (_serviceTableLock) this._serviceTable = null; this._log.Debug("由于服务发生变更,服务配置表被清空"); }
private Type[] FilterANotInB(ServiceConfigTable a, ServiceConfigTable b) { return(a.Services .Where(o => b.Services.FirstOrDefault(p => p.Type == o.Type) == null) .Select(o => o.Type).ToArray()); }
/// <summary> /// 尝试刷新关联节点配置,返回是否需要刷新服务表 /// </summary> /// <returns>是否需要刷新服务表_serviceTable</returns> private bool RefreshAssociate() { if (this.AssociateUri == null) { return(false); } //以下代码段均在线程安全前提下 #region 检查关联节点是否可连接 Exception ex; if (!this._remoteHandle.TryConnect(this.AssociateUri, null, out ex)) { //仅移除来自关联节点的服务配置 this._associateTable.Services.ToList().ForEach(o => o.Configs = o.Configs.Where(p => !p.HostUri.Equals(this.AssociateUri)).ToArray()); //仅移除没有可用服务配置的服务 this._container.ClearRemoteServices(this._associateTable.Services .Where(o => o.Configs.Length == 0) .Select(o => o.Type) .ToArray()); //关联节点不存在后保留原始配置可以进行正常调用 this._log.Warn("连接关联节点时发生异常,来自该节点内的远程服务已被卸载,其余服务保留", ex); return(true); } #endregion #region 检查版本 try { if (this._associateTable.Version.Equals(this._remoteHandle.GetVersion(this.AssociateUri))) { return(false); } } catch (Exception e) { this._log.Warn("检查关联节点服务表版本时发生异常", e); return(false); } #endregion #region 重新向本地容器注册关联节点的远程服务并清空配置表 try { var configs = this._remoteHandle.GetServiceConfigs(this.AssociateUri); //重试一次,防止意外情况造成的空列表 if (configs == null || configs.Services.Length == 0) { configs = this._remoteHandle.GetServiceConfigs(this.AssociateUri); } if (configs == null || configs.Services.Length == 0) { this._log.InfoFormat("从关联节点获取到空列表"); } //包含刷新容器和配置表逻辑 this.RefreshContainer(configs ?? new ServiceConfigTable()); } catch (Exception e) { this._log.Warn("刷新关联服务节点时发生异常", e); if (this._associateTable == null) { this._associateTable = new ServiceConfigTable(); } } #endregion #region 重新将本地服务注册至关联节点 try { if (this._localTable.Count > 0) { this._remoteHandle.Register(this.AssociateUri, this._localTable.ToArray()); this._log.Debug("将本地服务重新注册至关联节点"); } } catch (Exception e) { this._log.Warn("将本地服务重新注册至关联节点时发生异常", e); } #endregion return(false); }