任务

  1. 运行examples下面的 http服务
  2. 学习文档,结合divde插件,发起http请求soul网关,体验http代理
  3. 昨天已经体验了 http 代理的转发,今天来探索下 http 代理中的一些原理。

思考

关联 soul 的包

  • soul-spring-boot-starter-client-springmvc
  • soul-client-springmvc

服务注册

昨天已经发现 @SoulSpringMvcClient 可以定义规则,然后将规则注册到网关的选择器中。另外,通过配置文件中的配置项 soul.http 可以定义选择器的名称,而配置是通过 SoulSpringMvcClientConfiguration 进行装载。

1
2
3
4
5
6
7
soul:
http:
adminUrl: http://localhost:9095
port: 8188
contextPath: /http
appName: http
full: false
1
2
3
4
5
@Bean
@ConfigurationProperties(prefix = "soul.http")
public SoulSpringMvcConfig soulHttpConfig() {
return new SoulSpringMvcConfig();
}

大概知道了选择器的装载过程,我们来看看选择器是如何加载到 admin 控制台的。从 SoulSpringMvcClientConfiguration 可以看到,加载了 bean SpringMvcClientBeanPostProcessor。而这个类就是在 spring 加载 bean 之前进行预处理。

大致的逻辑就是:

  1. 在 spring 加载 bean 之前,先找所有 controller、restController、requestMapping 注解的 bean 。
  2. 在类上找是否有注解 @SoulSpringMvcClient,如果有,则查找是否含有 * ,将其注册到控制台。
  3. 在方法上找是否有注解 @SoulSpringMvcClient,如果有,则注册到控制台。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//1
Controller controller = AnnotationUtils.findAnnotation(bean.getClass(), Controller.class);
RestController restController = AnnotationUtils.findAnnotation(bean.getClass(), RestController.class);
RequestMapping requestMapping = AnnotationUtils.findAnnotation(bean.getClass(), RequestMapping.class);
...
//2
SoulSpringMvcClient clazzAnnotation = AnnotationUtils.findAnnotation(bean.getClass(), SoulSpringMvcClient.class);
String prePath = "";
if (Objects.nonNull(clazzAnnotation)) {
if (clazzAnnotation.path().indexOf("*") > 1) {
String finalPrePath = prePath;
executorService.execute(() -> RegisterUtils.doRegister(buildJsonParams(clazzAnnotation, finalPrePath), url,
RpcTypeEnum.HTTP));
return bean;
}
...
}
//3
final Method[] methods = ReflectionUtils.getUniqueDeclaredMethods(bean.getClass());
for (Method method : methods) {
SoulSpringMvcClient soulSpringMvcClient = AnnotationUtils.findAnnotation(method, SoulSpringMvcClient.class);
if (Objects.nonNull(soulSpringMvcClient)) {
...//注册
}
}

接下来,就是关键的工具类 RegisterUtils 的注册如何实现了,可以看到其就是利用 OkHttpTools 发送了 http 请求,重点在 url 和 json。 可以看到, url 由 adminUrl + “/soul-client/springmvc-register” 拼接而成,而 json 其实就是将 soul.http 的参数进行序列化。这里的重点是 /springmvc-register

1
2
3
4
public static void doRegister(final String json, final String url, final RpcTypeEnum rpcTypeEnum) {
String result = OkHttpTools.getInstance().post(url, json);
...
}

同时,我们可以关注 ContextRegisterListener 监听类,其实在SoulSpringMvcClientConfiguration中同样有加载,监听的逻辑和SpringMvcClientBeanPostProcessor类似。

回到 /springmvc-register 这个path,其实就是一个简单的http连接,调用admin的接口。而这个接口的逻辑,就是数据库保存功能。

1
2
3
4
@PostMapping("/springmvc-register")
public String registerSpringMvc(@RequestBody final SpringMvcRegisterDTO springMvcRegisterDTO) {
return soulClientRegisterService.registerSpringMvc(springMvcRegisterDTO);
}

此时,可以关注一下 admin 的表结构设计(这里只是一个搬运工),可以看到,selector 中应该就是存放我们定义的选择器,而 rule 中就是存放我们注册的规则。

image.png

image.png

image.png

至此,http 的注册逻辑就大致完成了。

HTTP 代理的实现

http 服务注册到了控制台,之后是怎么通过网关进行转发的呢?

后续可以通过网关入手,观察路由是如何进行跳转的。