实验环境
- JDK:
adopt-openjdk-1.8.0_292
- SpringBoot:
2.5.3
- SpringCloud:
2020.0.3
准备条件
(1)Maven 依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
(2)接收请求的 DemoController
@RestController
@Slf4j
@RequiredArgsConstructor
public class DemoController {
private final DemoClient demoClient;
@SneakyThrows
@GetMapping("/test")
public String testGet(HttpServletRequest request) {
log.info("[testGet] remote ip:port = {}:{}", request.getRemoteHost(), request.getRemotePort());
Thread.sleep(1 * 1000);
return "testGet";
}
@GetMapping("/test-feign")
public String testFeign(HttpServletRequest request) {
log.info("[testFeign] remote ip:port = {}:{}", request.getRemoteHost(), request.getRemotePort());
String result = demoClient.testGet();
log.info("result:{}", result);
return "testFeign";
}
}
(3)调用远程接口的 FeignClient
@FeignClient(value = "demo", url = "http://127.0.0.1:8080")
public interface DemoClient {
@GetMapping("/test")
String testGet();
}
实验
(一)使用默认的 Feign
配置
@Slf4j
public class DemoTest {
public static void main(String[] args) throws Exception {
String requestUrl = "http://127.0.0.1:8080/test-feign";
testGet(requestUrl);
}
@SneakyThrows
public static void testGet(String requestUrl) {
final URL url = new URL(requestUrl);
final HttpURLConnection connection = (HttpURLConnection) url.openConnection();
// 如果还没有建立过socket 连接,则建立 socket 连接
// 如果建立过 socket 连接,则直接从缓存中取出一个可用的
// 发送 http 请求
List<String> lines = IOUtils.readLines(connection.getInputStream());
lines.forEach(System.out::println);
}
}
执行三次 main()
方法,服务端控制台输出:
2021-07-26 14:15:43.027 INFO 1536 --- [nio-8080-exec-1] com.example.demo.DemoController : [testFeign] remote ip:port = 127.0.0.1:11992
2021-07-26 14:15:43.037 INFO 1536 --- [nio-8080-exec-2] com.example.demo.DemoController : [testGet] remote ip:port = 127.0.0.1:11995
2021-07-26 14:15:44.076 INFO 1536 --- [nio-8080-exec-1] com.example.demo.DemoController : result:testGet
2021-07-26 14:15:46.861 INFO 1536 --- [nio-8080-exec-4] com.example.demo.DemoController : [testFeign] remote ip:port = 127.0.0.1:12000
2021-07-26 14:15:46.863 INFO 1536 --- [nio-8080-exec-5] com.example.demo.DemoController : [testGet] remote ip:port = 127.0.0.1:11995
2021-07-26 14:15:47.869 INFO 1536 --- [nio-8080-exec-4] com.example.demo.DemoController : result:testGet
2021-07-26 14:15:51.001 INFO 1536 --- [nio-8080-exec-7] com.example.demo.DemoController : [testFeign] remote ip:port = 127.0.0.1:12008
2021-07-26 14:15:51.003 INFO 1536 --- [nio-8080-exec-8] com.example.demo.DemoController : [testGet] remote ip:port = 127.0.0.1:11995
2021-07-26 14:15:52.019 INFO 1536 --- [nio-8080-exec-7] com.example.demo.DemoController : result:testGet
源码解析:
package feign;
final class SynchronousMethodHandler implements MethodHandler {
@Override
public Object invoke(Object[] argv) throws Throwable {
RequestTemplate template = buildTemplateFromArgs.create(argv);
Options options = findOptions(argv);
return executeAndDecode(template, options);
}
Object executeAndDecode(RequestTemplate template, Options options) throws Throwable {
Request request = targetRequest(template);
Response response;
// 调用 client 执行实际的 http 请求
response = client.execute(request, options);
}
}
// 提交 HTTP 请求。 实现应该是线程安全的。
public interface Client {
// 针对其 request.url() 执行请求并返回响应。
Response execute(Request request, Options options) throws IOException;
class Default implements Client {
@Override
public Response execute(Request request, Options options) throws IOException {
HttpURLConnection connection = convertAndSend(request, options);
return convertResponse(connection, request);
}
HttpURLConnection convertAndSend(Request request, Options options) throws IOException {
final URL url = new URL(request.url());
final HttpURLConnection connection = this.getConnection(url);
// 设置连接超时时间
connection.setConnectTimeout(options.connectTimeoutMillis());
// 设置读超时时间
connection.setReadTimeout(options.readTimeoutMillis());
if (request.body() != null) {
// 如果当前请求有 body 需要发送,则调用 OutputStream 的 write() 方法
connection.setDoOutput(true);
OutputStream out = connection.getOutputStream();
out.write(request.body());
}
return connection;
}
Response convertResponse(HttpURLConnection connection, Request request) throws IOException {
// 1. getResponseCode() 方法中会调用 getInputStream() 方法,确认已经连接到服务器,并发送了 http 请求
int status = connection.getResponseCode();
String reason = connection.getResponseMessage();
return Response.builder()
.status(status)
.reason(reason)
.headers(headers)
.request(request)
.body(stream, length)
.build();
}
}
}
网友评论