Spring Cloud Gateway根據Path動態配置路由

Spring Cloud Gateway-2

​ spring cloud 網關提供了很多路由規則,但是用的較多的還是根據路徑進行轉發。

例如:

  • /user開頭轉發到user服務
  • /file開頭轉發到file服務

如上設置,在使用nginx 是可以完成的,但是弊端是如果只有這兩個服務還好,如果是10個或者50個服務呢?還可以一一的進行配置麼?那豈不很麻煩?

那使用spring cloud gateway的動態網關即可省去這麼麻煩的配置操作;

根據路徑進行配置路由規則

實現思路

  1. 網關直接啓動不需要任何配置
  2. 每個服務啓動之後掃描有@Controller或者@RestController的類
  3. 或者有註解的類,並且獲取註解Value值
  4. 根據註解的value通過網關API創建路由和刷新路由

import com.user.service.GatewayService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 * Created by likuo on 2019/11/10.
 */
@Component
public class ClassScan  implements ApplicationRunner {
    @Value("${spring.application.name}")
    private String serviceName;
    @Autowired
    private GatewayService gatewayService;
    @Override
    public void run(ApplicationArguments applicationArguments) throws Exception {
        try {
            // 第二步獲取包名下所有類
            Set<Class<?>> classes = getClasses("com.user.controller");
            List<Predicates> list = new ArrayList<>();
            JsonRootBean jsonRootBean = new JsonRootBean();
            for(Class c:classes){
                // 打印有RestController 的類 當然如果有使用Controller註解,也可以在此判斷
                if(c.isAnnotationPresent(RestController.class)){
                    // 獲取該類的RequestMapping註解
                    RequestMapping annotation = (RequestMapping)c.getAnnotation(RequestMapping.class);
                    jsonRootBean.setId(UUID.randomUUID().toString());
                    // service名稱要大寫免得出問題
                    // 即使小寫的名稱,註冊到Eureka Server 上, 在頁碼顯示的還是大寫的名稱
                    jsonRootBean.setUri("lb://"+serviceName.toUpperCase());
                    Predicates predicates = new Predicates();
                    // 根據路徑進行
                    predicates.setName("Path");
                    Map<String,String> map = new HashMap<>();
                    // RequestMapping 可以設置多個path(@RequestMapping(value = {"/user","userinfo"})) 因爲我現在只寫了一個,所以獲取第一個即可
                    String path = annotation.value()[0]+"/**";
                    System.out.println(path);
                    map.put("_genkey_0",path);
                    predicates.setArgs(map);
                    list.add(predicates);
                    System.out.println(  annotation.value());
                }
            }
            jsonRootBean.setPredicates(list);
            //創建路由規則
            gatewayService.create(jsonRootBean);
            // 刷新路由規則
            gatewayService.refresh();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

GatewayService.java

@FeignClient("EUREKA-CLIENT-GATEWAY")
public interface GatewayService {
    @RequestMapping(method = RequestMethod.POST,value = "/actuator/gateway/routes/user")
    String create(JsonRootBean jsonRootBean);
    @RequestMapping(method = RequestMethod.POST,value = "/actuator/gateway/refresh")
    String refresh();
}

如上getClasses 方法到 點擊跳轉

源碼傳送https://download.csdn.net/download/qq_30285985/11971236

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章