Spring Cloud Gateway-2
spring cloud 网关提供了很多路由规则,但是用的较多的还是根据路径进行转发。
例如:
/user
开头转发到user服务/file
开头转发到file服务
如上设置,在使用nginx
是可以完成的,但是弊端是如果只有这两个服务还好,如果是10个或者50个服务呢?还可以一一的进行配置么?那岂不很麻烦?
那使用spring cloud gateway的动态网关即可省去这么麻烦的配置操作;
根据路径进行配置路由规则
实现思路
- 网关直接启动不需要任何配置
- 每个服务启动之后扫描有
@Controller
或者@RestController
的类 - 或者有注解的类,并且获取注解Value值
- 根据注解的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 方法到 点击跳转