Skip to content

Commit 58d089b

Browse files
authored
新增 Spring Cloud OpenFeign 源码分析 (doocs#136)
1 parent 3207d4f commit 58d089b

3 files changed

Lines changed: 720 additions & 15 deletions

File tree

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,11 @@
117117
- [SpringBoot 日志系统](/docs/SpringBoot/SpringBoot-LogSystem.md)
118118
- [SpringBoot ConditionalOnBean](/docs/SpringBoot/SpringBoot-ConditionalOnBean.md)
119119

120+
## Spring Cloud
121+
122+
- [Spring Cloud Commons 源码](docs/SpringCloud/spring-cloud-commons-source-note.md)
123+
- [Spring Cloud OpenFeign 源码](docs/SpringCloud/spring-cloud-openfeign-source-note.md)
124+
120125
### SpringSecurity
121126

122127
- [SpringSecurity 请求全过程解析](/docs/SpringSecurity/SpringSecurity请求全过程解析.md)

docs/SpringCloud/spring-cloud-commons-source-note.md

Lines changed: 158 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,32 @@ SpringCloud 是在 SpringBoot 的基础上构建的。Spring Cloud 以两个库
2323

2424
[前置知识:SprinBoot 加载 application.yml 的原理](https://github.com/haitaoss/spring-boot/blob/source-v2.7.8/note/springboot-source-note.md#%E5%B1%9E%E6%80%A7%E6%96%87%E4%BB%B6%E7%9A%84%E5%8A%A0%E8%BD%BD%E9%A1%BA%E5%BA%8F)
2525

26-
[示例代码](https://github.com/haitaoss/spring-cloud-commons/tree/source-v3.1.5/source-note-spring-cloud-commons/src/main/java/cn/haitaoss/BootstrapProperties/Main.java)
26+
示例代码
27+
28+
```java
29+
@EnableAutoConfiguration
30+
public class Main {
31+
32+
public static void main(String[] args) {
33+
// 是否创建 bootstrapContext
34+
System.setProperty("spring.cloud.bootstrap.enabled", "true");
35+
// 设置 bootstrapContext 中属性文件的搜索目录 或者是 属性文件
36+
System.setProperty("spring.cloud.bootstrap.location", "");
37+
System.setProperty("spring.cloud.bootstrap.additional-location",
38+
"optional:classpath:/config/haitao/,classpath:/haitao.properties");
39+
// 设置 bootstrapContext 默认属性文件的名字
40+
// System.setProperty("spring.cloud.bootstrap.name", "bootstrap-haitao");
41+
// 设置 profile
42+
// System.setProperty("spring.profiles.active", "haitao");
43+
// 测试读取属性
44+
ConfigurableApplicationContext context = SpringApplication.run(Main.class, args);
45+
ConfigurableEnvironment environment = context.getEnvironment();
46+
Stream.iterate(1, i -> i + 1).limit(5).map(i -> "p" + i).forEach(
47+
name -> System.out.println(String.format("key:%s \t valus: %s", name, environment.getProperty(name))));
48+
}
49+
50+
}
51+
```
2752

2853
BootstrapApplicationListener 是用于完成 SpringCloud 的接入的,主要是完成 bootstrapContext 的创建、bootstrap 属性的加载、设置 bootstrapContext 为父容器。下面是 BootstrapApplicationListener 被触发的入口和核心逻辑
2954

@@ -109,7 +134,43 @@ public class BootstrapImportSelectorConfiguration {}
109134

110135
### PropertySourceBootstrapConfiguration
111136

112-
[示例代码](https://github.com/haitaoss/spring-cloud-commons/tree/source-v3.1.5/source-note-spring-cloud-commons/src/main/java/cn/haitaoss/BootstrapProperties/BootstrapConfiguration/MyPropertySourceLocator.java)
137+
示例代码
138+
139+
```java
140+
public class MyPropertySourceLocator implements PropertySourceLocator {
141+
142+
public MyPropertySourceLocator() {
143+
System.out.println("MyPropertySourceLocator...构造器");
144+
}
145+
146+
@Resource
147+
private ApplicationContext applicationContext;
148+
149+
@Value("${dynamicConfigFile}")
150+
private String filePath;
151+
152+
@Override
153+
public PropertySource<?> locate(Environment environment) {
154+
PropertySource<?> propertySource;
155+
try {
156+
// 也可以改成网络资源
157+
propertySource = new YamlPropertySourceLoader()
158+
.load("haitao-propertySource", applicationContext.getResource(filePath)).get(0);
159+
} catch (IOException e) {
160+
throw new RuntimeException(e);
161+
}
162+
return propertySource;
163+
}
164+
165+
}
166+
```
167+
168+
`META-INF/spring.factories`
169+
170+
```properties
171+
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
172+
cn.haitaoss.BootstrapProperties.BootstrapConfiguration.MyPropertySourceLocator
173+
```
113174

114175
```java
115176
/**
@@ -154,7 +215,39 @@ public class BootstrapImportSelectorConfiguration {}
154215

155216
## @RefreshScope@ConfigurationProperties bean 的更新
156217

157-
[示例代码](https://github.com/haitaoss/spring-cloud-commons/tree/source-v3.1.5/source-note-spring-cloud-commons/src/main/java/cn/haitaoss/refresh/Main.java)
218+
示例代码
219+
220+
```java
221+
@SpringBootApplication
222+
public class Main {
223+
224+
/**
225+
* 总结用法:
226+
*
227+
* 可以通过属性 spring.cloud.refresh.refreshable spring.cloud.refresh.extraRefreshable
228+
* 代替 @RefreshScope
229+
*
230+
* 可以设置属性 spring.cloud.refresh.enabled=false 取消 @RefreshScope 的自动注入 是
231+
* spring.cloud.refresh.never-refreshable 属性记录的类就不重会新绑定属性
232+
*/
233+
public static void main(String[] args) {
234+
// TODOHAITAO: 2023/4/6 访问验证属性更新 GET http://127.0.0.1:8080/actuator/refresh
235+
// 启用 bootstrap 属性的加载
236+
System.setProperty("spring.cloud.bootstrap.enabled", "true");
237+
238+
// 通过配置属性的方式,扩展bean为 refresh scope 的
239+
System.setProperty("spring.cloud.refresh.refreshable",
240+
Arrays.asList(RefreshScopeBean1.class.getName(), RefreshScopeBean2.class.getName()).stream()
241+
.collect(Collectors.joining(",")));
242+
System.setProperty("spring.cloud.refresh.extraRefreshable",
243+
Arrays.asList(Object.class.getName()).stream().collect(Collectors.joining(",")));
244+
245+
// 设置 bootstrapContext 会默认加载的 bean
246+
System.setProperty("spring.cloud.bootstrap.sources","cn.haitaoss.RefreshScope.config.MyPropertySourceLocator");
247+
}
248+
249+
}
250+
```
158251

159252
```java
160253
/**
@@ -438,7 +531,29 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
438531

439532
## LoadBalancerClient
440533

441-
[示例代码](https://github.com/haitaoss/spring-cloud-commons/tree/source-v3.1.5/source-note-spring-cloud-commons/src/main/java/cn/haitaoss/ServiceRegisterAndLoadBalance/Main.java)
534+
示例代码
535+
536+
```java
537+
@EnableAutoConfiguration
538+
@RestController
539+
@Import({ LoadBalancerClientConfig.class, LoadBalancerOtherConfig.class })
540+
public class Main extends BaseApp {
541+
542+
public static void main(String[] args) {
543+
/**
544+
* TODOHAITAO: 2023/4/7 验证方式 运行 Main、Client1、Client2 然后访问:
545+
* - 堵塞式 GET http://localhost:8080/s1
546+
* - 响应式 GET http://localhost:8080/2/s1
547+
*/
548+
// 采用那种方式对 RestTemplate 进行增强,看
549+
// org.springframework.cloud.client.loadbalancer.LoadBalancerAutoConfiguration
550+
System.setProperty("spring.cloud.loadbalancer.retry.enabled", "false");
551+
System.setProperty("spring.profiles.active", "loadbalance");
552+
ConfigurableApplicationContext context = SpringApplication.run(Main.class);
553+
}
554+
555+
}
556+
```
442557

443558
负载均衡会使用 LoadBalancerClient 来执行请求的,大致逻辑是通过 DiscoveryClient 得到 serviceId 有哪些实例,再通过负载均衡策略的逻辑筛选出唯一的实例,然后根据这个实例的 url 执行请求。
444559

@@ -720,7 +835,16 @@ spring.cloud.loadbalancer.retry.backoff.jitter=1
720835

721836
### ReactorLoadBalancer
722837

723-
[示例代码](https://github.com/haitaoss/spring-cloud-commons/tree/source-v3.1.5/source-note-spring-cloud-commons/src/main/java/cn/haitaoss/ServiceRegisterAndLoadBalance/loadbalancer/LoadBalancerClientConfig.java)
838+
示例代码
839+
840+
```java
841+
@LoadBalancerClient(name = "s1", configuration = { MyLoadBalancer.class, MyServiceInstanceListSupplier.class })
842+
@LoadBalancerClients({ @LoadBalancerClient(name = "s2", configuration = MyRandomLoadBalancer.class),
843+
@LoadBalancerClient(name = "s3", configuration = MyRoundRobinLoadBalancer.class), })
844+
public class LoadBalancerClientConfig {
845+
846+
}
847+
```
724848

725849
```java
726850
/**
@@ -783,7 +907,28 @@ public class LoadBalancerClientConfiguration {
783907

784908
### ServiceInstanceListSupplier
785909

786-
[示例代码](https://github.com/haitaoss/spring-cloud-commons/tree/source-v3.1.5/source-note-spring-cloud-commons/src/main/java/cn/haitaoss/ServiceRegisterAndLoadBalance/loadbalancer/MyServiceInstanceListSupplier.java)
910+
示例代码
911+
912+
```java
913+
public class MyServiceInstanceListSupplier {
914+
915+
@Bean
916+
public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(
917+
ConfigurableApplicationContext context) {
918+
return ServiceInstanceListSupplier.builder()
919+
//.withDiscoveryClient() // 通过 ReactiveDiscoveryClient 获取 List<ServiceInstance>
920+
.withBlockingDiscoveryClient() // 通过 DiscoveryClient 获取 List<ServiceInstance>
921+
// 下面配置的是通过什么方式 过滤 List<ServiceInstance>
922+
// .withZonePreference() // spring.cloud.loadbalancer.zone" 属性值与 serviceInstance.getMetadata().get("zone") 进行匹配
923+
// .withBlockingHealthChecks() // spring.cloud.loadbalancer.healthCheck.* 属性定义的的规则来过滤
924+
// .withRequestBasedStickySession() spring.cloud.loadbalancer.stickySession.instanceIdCookieName 属性值过滤 serviceInstance.getInstanceId()
925+
// .withSameInstancePreference()
926+
.withCaching() // 会使用到 LoadBalancerCacheManager 缓存 List<ServiceInstance>
927+
.build(context);
928+
}
929+
930+
}
931+
```
787932

788933
```java
789934
/**
@@ -803,15 +948,15 @@ public class LoadBalancerClientConfiguration {
803948
```java
804949
public interface ServiceInstanceListSupplier extends Supplier<Flux<List<ServiceInstance>>> {
805950

806-
String getServiceId();
951+
String getServiceId();
807952

808-
default Flux<List<ServiceInstance>> get(Request request) {
809-
return get();
810-
}
953+
default Flux<List<ServiceInstance>> get(Request request) {
954+
return get();
955+
}
811956

812-
static ServiceInstanceListSupplierBuilder builder() {
813-
return new ServiceInstanceListSupplierBuilder();
814-
}
957+
static ServiceInstanceListSupplierBuilder builder() {
958+
return new ServiceInstanceListSupplierBuilder();
959+
}
815960

816961
}
817962
```
@@ -820,8 +965,6 @@ public interface ServiceInstanceListSupplier extends Supplier<Flux<List<ServiceI
820965

821966
WebClient.Builder 是执行响应式请求的工具类。下面是让 WebClient.Builder 具有负载均衡能力的实现逻辑。
822967

823-
[示例代码](https://github.com/haitaoss/spring-cloud-commons/tree/source-v3.1.5/source-note-spring-cloud-commons/src/main/java/cn/haitaoss/ServiceRegisterAndLoadBalance/loadbalancer/LoadBalancerOtherConfig.java)
824-
825968
`spring-cloud-commons.jar!/META-INF/spring.factories`的部分内容
826969

827970
```properties

0 commit comments

Comments
 (0)