b08a7f88d5dbdea951e19e43e329cf32d7e57af8.svn-base 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. package org.jeecg.loader;
  2. import cn.hutool.core.util.ObjectUtil;
  3. import com.alibaba.fastjson.JSON;
  4. import com.alibaba.fastjson.JSONArray;
  5. import com.alibaba.fastjson.JSONObject;
  6. import com.alibaba.nacos.api.NacosFactory;
  7. import com.alibaba.nacos.api.config.ConfigService;
  8. import com.alibaba.nacos.api.config.listener.Listener;
  9. import com.alibaba.nacos.api.exception.NacosException;
  10. import com.google.common.collect.Lists;
  11. import lombok.extern.slf4j.Slf4j;
  12. import org.apache.commons.lang.StringUtils;
  13. import org.jeecg.common.constant.CacheConstant;
  14. import org.jeecg.common.util.RedisUtil;
  15. import org.jeecg.config.GatewayRoutersConfiguration;
  16. import org.jeecg.config.RouterDataType;
  17. import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
  18. import org.springframework.cloud.gateway.filter.FilterDefinition;
  19. import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
  20. import org.springframework.cloud.gateway.route.InMemoryRouteDefinitionRepository;
  21. import org.springframework.cloud.gateway.route.RouteDefinition;
  22. import org.springframework.context.ApplicationEventPublisher;
  23. import org.springframework.context.ApplicationEventPublisherAware;
  24. import org.springframework.context.annotation.DependsOn;
  25. import org.springframework.stereotype.Component;
  26. import reactor.core.publisher.Mono;
  27. import javax.annotation.PostConstruct;
  28. import java.net.URI;
  29. import java.net.URISyntaxException;
  30. import java.util.ArrayList;
  31. import java.util.List;
  32. import java.util.Properties;
  33. import java.util.concurrent.Executor;
  34. /**
  35. * 动态路由加载器
  36. *
  37. * @author : zyf
  38. * @date :2020-11-10
  39. */
  40. @Slf4j
  41. @Component
  42. @DependsOn({"gatewayRoutersConfiguration"})
  43. public class DynamicRouteLoader implements ApplicationEventPublisherAware {
  44. private ApplicationEventPublisher publisher;
  45. private InMemoryRouteDefinitionRepository repository;
  46. private DynamicRouteService dynamicRouteService;
  47. private ConfigService configService;
  48. private RedisUtil redisUtil;
  49. public DynamicRouteLoader(InMemoryRouteDefinitionRepository repository, DynamicRouteService dynamicRouteService, RedisUtil redisUtil) {
  50. this.repository = repository;
  51. this.dynamicRouteService = dynamicRouteService;
  52. this.redisUtil = redisUtil;
  53. }
  54. @PostConstruct
  55. public void init() {
  56. String dataType = GatewayRoutersConfiguration.DATA_TYPE;
  57. log.info("初始化路由,dataType:"+ dataType);
  58. if (RouterDataType.nacos.toString().endsWith(dataType)) {
  59. loadRoutesByNacos();
  60. }
  61. //从数据库加载路由
  62. if (RouterDataType.database.toString().endsWith(dataType)) {
  63. loadRoutesByRedis();
  64. }
  65. }
  66. /**
  67. * 刷新路由
  68. *
  69. * @return
  70. */
  71. public Mono<Void> refresh() {
  72. String dataType = GatewayRoutersConfiguration.DATA_TYPE;
  73. if (!RouterDataType.yml.toString().endsWith(dataType)) {
  74. this.init();
  75. }
  76. return Mono.empty();
  77. }
  78. /**
  79. * 从nacos中读取路由配置
  80. *
  81. * @return
  82. */
  83. private void loadRoutesByNacos() {
  84. List<RouteDefinition> routes = Lists.newArrayList();
  85. configService = createConfigService();
  86. if (configService == null) {
  87. log.warn("initConfigService fail");
  88. }
  89. try {
  90. String configInfo = configService.getConfig(GatewayRoutersConfiguration.DATA_ID, GatewayRoutersConfiguration.ROUTE_GROUP, GatewayRoutersConfiguration.DEFAULT_TIMEOUT);
  91. if (StringUtils.isNotBlank(configInfo)) {
  92. log.info("获取网关当前配置:\r\n{}", configInfo);
  93. routes = JSON.parseArray(configInfo, RouteDefinition.class);
  94. }
  95. } catch (NacosException e) {
  96. log.error("初始化网关路由时发生错误", e);
  97. e.printStackTrace();
  98. }
  99. for (RouteDefinition definition : routes) {
  100. log.info("update route : {}", definition.toString());
  101. dynamicRouteService.add(definition);
  102. }
  103. this.publisher.publishEvent(new RefreshRoutesEvent(this));
  104. dynamicRouteByNacosListener(GatewayRoutersConfiguration.DATA_ID, GatewayRoutersConfiguration.ROUTE_GROUP);
  105. }
  106. /**
  107. * 从redis中读取路由配置
  108. *
  109. * @return
  110. */
  111. private void loadRoutesByRedis() {
  112. List<MyRouteDefinition> routes = Lists.newArrayList();
  113. configService = createConfigService();
  114. if (configService == null) {
  115. log.warn("initConfigService fail");
  116. }
  117. Object configInfo = redisUtil.get(CacheConstant.GATEWAY_ROUTES);
  118. if (ObjectUtil.isNotEmpty(configInfo)) {
  119. log.info("获取网关当前配置:\r\n{}", configInfo);
  120. JSONArray array = JSON.parseArray(configInfo.toString());
  121. try {
  122. routes = getRoutesByJson(array);
  123. } catch (URISyntaxException e) {
  124. e.printStackTrace();
  125. }
  126. }
  127. for (MyRouteDefinition definition : routes) {
  128. log.info("update route : {}", definition.toString());
  129. Integer status=definition.getStatus();
  130. if(status.equals(0)){
  131. dynamicRouteService.delete(definition.getId());
  132. }else{
  133. dynamicRouteService.add(definition);
  134. }
  135. }
  136. this.publisher.publishEvent(new RefreshRoutesEvent(this));
  137. }
  138. /**
  139. * redis中的信息需要处理下 转成RouteDefinition对象
  140. * - id: login
  141. * uri: lb://cloud-jeecg-system
  142. * predicates:
  143. * - Path=/jeecg-boot/sys/**,
  144. *
  145. * @param array
  146. * @return
  147. */
  148. public static List<MyRouteDefinition> getRoutesByJson(JSONArray array) throws URISyntaxException {
  149. List<MyRouteDefinition> ls = new ArrayList<>();
  150. for (int i = 0; i < array.size(); i++) {
  151. JSONObject obj = array.getJSONObject(i);
  152. MyRouteDefinition route = new MyRouteDefinition();
  153. route.setId(obj.getString("routerId"));
  154. route.setStatus(obj.getInteger("status"));
  155. Object uri = obj.get("uri");
  156. if (uri == null) {
  157. route.setUri(new URI("lb://" + obj.getString("name")));
  158. } else {
  159. route.setUri(new URI(obj.getString("uri")));
  160. }
  161. Object predicates = obj.get("predicates");
  162. if (predicates != null) {
  163. JSONArray list = JSON.parseArray(predicates.toString());
  164. List<PredicateDefinition> predicateDefinitionList = new ArrayList<>();
  165. for (Object map : list) {
  166. JSONObject json = (JSONObject) map;
  167. PredicateDefinition predicateDefinition = new PredicateDefinition();
  168. predicateDefinition.setName(json.getString("name"));
  169. JSONArray jsonArray = json.getJSONArray("args");
  170. for (int j = 0; j < jsonArray.size(); j++) {
  171. predicateDefinition.addArg("_genkey" + j, jsonArray.get(j).toString());
  172. }
  173. predicateDefinitionList.add(predicateDefinition);
  174. }
  175. route.setPredicates(predicateDefinitionList);
  176. }
  177. Object filters = obj.get("filters");
  178. if (filters != null) {
  179. JSONArray list = JSON.parseArray(filters.toString());
  180. List<FilterDefinition> filterDefinitionList = new ArrayList<>();
  181. if (ObjectUtil.isNotEmpty(list)) {
  182. for (Object map : list) {
  183. JSONObject json = (JSONObject) map;
  184. JSONArray jsonArray = json.getJSONArray("args");
  185. String name = json.getString("name");
  186. FilterDefinition filterDefinition = new FilterDefinition();
  187. for (Object o : jsonArray) {
  188. JSONObject params = (JSONObject) o;
  189. filterDefinition.addArg(params.getString("key"), params.get("value").toString());
  190. }
  191. filterDefinition.setName(name);
  192. filterDefinitionList.add(filterDefinition);
  193. }
  194. route.setFilters(filterDefinitionList);
  195. }
  196. }
  197. ls.add(route);
  198. }
  199. return ls;
  200. }
  201. // private void loadRoutesByDataBase() {
  202. // List<GatewayRouteVo> routeList = jdbcTemplate.query(SELECT_ROUTES, new RowMapper<GatewayRouteVo>() {
  203. // @Override
  204. // public GatewayRouteVo mapRow(ResultSet rs, int i) throws SQLException {
  205. // GatewayRouteVo result = new GatewayRouteVo();
  206. // result.setId(rs.getString("id"));
  207. // result.setName(rs.getString("name"));
  208. // result.setUri(rs.getString("uri"));
  209. // result.setStatus(rs.getInt("status"));
  210. // result.setRetryable(rs.getInt("retryable"));
  211. // result.setPredicates(rs.getString("predicates"));
  212. // result.setStripPrefix(rs.getInt("strip_prefix"));
  213. // result.setPersist(rs.getInt("persist"));
  214. // return result;
  215. // }
  216. // });
  217. // if (ObjectUtil.isNotEmpty(routeList)) {
  218. // // 加载路由
  219. // routeList.forEach(route -> {
  220. // RouteDefinition definition = new RouteDefinition();
  221. // List<PredicateDefinition> predicatesList = Lists.newArrayList();
  222. // List<FilterDefinition> filtersList = Lists.newArrayList();
  223. // definition.setId(route.getId());
  224. // String predicates = route.getPredicates();
  225. // String filters = route.getFilters();
  226. // if (StringUtils.isNotEmpty(predicates)) {
  227. // predicatesList = JSON.parseArray(predicates, PredicateDefinition.class);
  228. // definition.setPredicates(predicatesList);
  229. // }
  230. // if (StringUtils.isNotEmpty(filters)) {
  231. // filtersList = JSON.parseArray(filters, FilterDefinition.class);
  232. // definition.setFilters(filtersList);
  233. // }
  234. // URI uri = UriComponentsBuilder.fromUriString(route.getUri()).build().toUri();
  235. // definition.setUri(uri);
  236. // this.repository.save(Mono.just(definition)).subscribe();
  237. // });
  238. // log.info("加载路由:{}==============", routeList.size());
  239. // Mono.empty();
  240. // }
  241. // }
  242. /**
  243. * 监听Nacos下发的动态路由配置
  244. *
  245. * @param dataId
  246. * @param group
  247. */
  248. public void dynamicRouteByNacosListener(String dataId, String group) {
  249. try {
  250. configService.addListener(dataId, group, new Listener() {
  251. @Override
  252. public void receiveConfigInfo(String configInfo) {
  253. log.info("进行网关更新:\n\r{}", configInfo);
  254. List<RouteDefinition> definitionList = JSON.parseArray(configInfo, RouteDefinition.class);
  255. for (RouteDefinition definition : definitionList) {
  256. log.info("update route : {}", definition.toString());
  257. dynamicRouteService.update(definition);
  258. }
  259. }
  260. @Override
  261. public Executor getExecutor() {
  262. log.info("getExecutor\n\r");
  263. return null;
  264. }
  265. });
  266. } catch (Exception e) {
  267. log.error("从nacos接收动态路由配置出错!!!", e);
  268. }
  269. }
  270. /**
  271. * 创建ConfigService
  272. *
  273. * @return
  274. */
  275. private ConfigService createConfigService() {
  276. try {
  277. Properties properties = new Properties();
  278. properties.setProperty("serverAddr", GatewayRoutersConfiguration.SERVER_ADDR);
  279. properties.setProperty("namespace", GatewayRoutersConfiguration.NAMESPACE);
  280. properties.setProperty("username",GatewayRoutersConfiguration.USERNAME);
  281. properties.setProperty("password",GatewayRoutersConfiguration.PASSWORD);
  282. return configService = NacosFactory.createConfigService(properties);
  283. } catch (Exception e) {
  284. log.error("创建ConfigService异常", e);
  285. return null;
  286. }
  287. }
  288. @Override
  289. public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
  290. this.publisher = applicationEventPublisher;
  291. }
  292. }