【spring系列】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

猜你喜欢

转载自blog.csdn.net/qq_30285985/article/details/103018968