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 方法到 點擊跳轉