001/** 002 * Copyright (c) 2015-2022, Michael Yang 杨福海 (fuhai999@gmail.com). 003 * <p> 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * <p> 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * <p> 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package io.jboot.components.gateway; 017 018import io.jboot.utils.ConfigUtil; 019import io.jboot.components.gateway.discovery.GatewayDiscovery; 020import io.jboot.components.gateway.discovery.GatewayDiscoveryManager; 021import io.jboot.components.gateway.discovery.GatewayInstance; 022import io.jboot.utils.StrUtil; 023 024import javax.servlet.http.HttpServletRequest; 025import java.util.HashSet; 026import java.util.List; 027import java.util.Map; 028import java.util.Set; 029import java.util.concurrent.ConcurrentHashMap; 030 031/** 032 * @author michael yang (fuhai999@gmail.com) 033 * @Date: 2020/3/21 034 */ 035public class JbootGatewayManager { 036 037 private static JbootGatewayManager me = new JbootGatewayManager(); 038 039 public static JbootGatewayManager me() { 040 return me; 041 } 042 043 private Map<String, JbootGatewayConfig> configMap; 044 private GatewayErrorRender gatewayErrorRender; 045 private GatewayDiscovery discovery; 046 047 048 private JbootGatewayManager() { 049 050 initDiscovery(); 051 052 initConfigs(); 053 } 054 055 private void initConfigs() { 056 Map<String, JbootGatewayConfig> configMap = ConfigUtil.getConfigModels(JbootGatewayConfig.class, "jboot.gateway"); 057 for (Map.Entry<String, JbootGatewayConfig> entry : configMap.entrySet()) { 058 if ("discovery".equals(entry.getKey()) || "instance".equals(entry.getKey())) { 059 continue; 060 } 061 JbootGatewayConfig config = entry.getValue(); 062 if (StrUtil.isBlank(config.getName())) { 063 config.setName(entry.getKey()); 064 } 065 registerConfig(config); 066 } 067 } 068 069 /** 070 * 初始化服务发现 071 */ 072 private void initDiscovery() { 073 this.discovery = GatewayDiscoveryManager.me().getGatewayDiscovery(); 074 } 075 076 public boolean isConfigOk() { 077 return configMap != null && !configMap.isEmpty(); 078 } 079 080 081 /** 082 * 动态注册新的路由配置 083 * 084 * @param config 配置信息 085 */ 086 public void registerConfig(JbootGatewayConfig config) { 087 if (configMap == null) { 088 configMap = new ConcurrentHashMap<>(); 089 } 090 configMap.put(config.getName(), config); 091 092 if (discovery != null) { 093 List<GatewayInstance> healthyInstances = discovery.selectInstances(config.getName(), true); 094 syncDiscoveryUris(healthyInstances, config); 095 096 discovery.subscribe(config.getName(), eventInfo -> { 097 List<GatewayInstance> changedInstances = eventInfo.getInstances(); 098 syncDiscoveryUris(changedInstances, config); 099 }); 100 } 101 102 if (config.isEnable()) { 103 JbootGatewayHealthChecker.me().start(); 104 } 105 } 106 107 private void syncDiscoveryUris(List<GatewayInstance> instances, JbootGatewayConfig config) { 108 if (instances == null) { 109 config.syncDiscoveryUris(null); 110 } else { 111 Set<String> uris = new HashSet<>(); 112 instances.forEach(instance -> { 113 if (instance.isHealthy()) { 114 uris.add(instance.getUri()); 115 } 116 }); 117 config.syncDiscoveryUris(uris); 118 } 119 } 120 121 122 /** 123 * 动态移除路由配置 124 * 125 * @param name 配置名称 126 * @return 被移除的配置信息 127 */ 128 public JbootGatewayConfig removeConfig(String name) { 129 return configMap == null ? null : configMap.remove(name); 130 } 131 132 133 /** 134 * 获取某个配置信息 135 * 136 * @param name 配置名称 137 * @return 配置信息 138 */ 139 public JbootGatewayConfig getConfig(String name) { 140 return configMap == null ? null : configMap.get(name); 141 } 142 143 144 /** 145 * 获取所有的配置信息 146 * 147 * @return 148 */ 149 public Map<String, JbootGatewayConfig> getConfigMap() { 150 return configMap; 151 } 152 153 /** 154 * 匹配可用的网关 155 * 156 * @param req 请求 157 * @return 返回匹配到的网关配置 158 */ 159 public JbootGatewayConfig matchingConfig(HttpServletRequest req) { 160 if (configMap != null && !configMap.isEmpty()) { 161 for (JbootGatewayConfig config : configMap.values()) { 162 if (config.isEnable() && config.matches(req)) { 163 return config; 164 } 165 } 166 } 167 return null; 168 } 169 170 public GatewayErrorRender getGatewayErrorRender() { 171 return gatewayErrorRender; 172 } 173 174 public void setGatewayErrorRender(GatewayErrorRender gatewayErrorRender) { 175 this.gatewayErrorRender = gatewayErrorRender; 176 } 177 178 179}