1 前言
Java 项目中接口调用是怎么做的?
- Httpclient:HttpClient 是 Apache Jakarta Common 下的子项目,用来提供高效的、最新的、功能丰富的支持 Http 协议的客户端编程工具包,并且它支持 Http 协议最新的版本和建议。HttpClient 相比传统的 JDK 自带的 URLConnection,增加了易用性和灵活性,是客户端发送 Http 请求变得容易,提高了开发效率。
- Okhttp:一个处理网络请求的开源项目,是安卓端最火的轻量级框架,由 Square 公司贡献,用于替代 HttpUrlConnection 和 Apache HttpClient。OkHttp 有简介的 API、高效的性能,并支持多种协议(Http/2 和 SPDY)。
- Httpurlconnection:Httpurlconnection 是 Java 的标准类,它继承自 URLConnection,可用于向指定网站发送 GET、POST 请求。HttpURLConnection 使用比较复杂,不像 HttpClient 那么容易使用。
- RestTemplate:RestTemplate 是 Spring 提供的用于访问 Rest 服务的客户端,RestTemplate 提供了多种便捷访问远程 Http 服务的方法,能够大大提高客户端的编写效率。
上面介绍的是最常见的集中调用接口的方法,我们下面是介绍的方法比上面的更简单方面,它是 Feign。
2 介绍
Feign 是一个声明式的 REST 客户端,它能让 REST 调用更加简单。Feign 提供了 Http 请求的模板,通过编写简单的忌口和插入注解,就可以定义好 Http 请求的参数、格式、地址等信息。
而 Feign 则会完全代理 Http 请求,我们只需要湘调用方法一样调用它就可以完成服务请求及相关处理。Spring Cloud 对 Feign 进行了封装,使其支持 Spring MVC 标准注解和 HttpMessaeConverters。Feign 可以与 Eureka 和 Ribbon 组合使用以支持负载均衡。
3 Spring Cloud 集成 Feign
- 创建 spring-cloud-web-admin-feign 项目,pom.xml 文件和之前的差不多,只是添加了如下依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
- 在启动类中添加 @EnableFeignClients 注解,如果你的 Feign 接口定义跟你的启动类不在一个包名下,还需要指定扫描的包名 @EnableFeignClients(basePackages = “com.pky.spring.cloud”),如下代码所示:
package com.pky.spring.cloud.web.admin.feign;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients(basePackages = "com.pky.spring.cloud")
public class WebAdminFeignApplication {
public static void main(String[] args) {
SpringApplication.run(WebAdminFeignApplication.class);
}
}
- 使用 Feign 调用接口
定义一个 Feign 的客户端,以接口的形式存在,这里调用之前 admin-provider 服务提供者的接口,代码如下:
package com.pky.spring.cloud.web.admin.feign.service;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
@FeignClient(value = "admin-provider", path = "/admin")
public interface AdminService {
@GetMapping(value = "")
public String testFeign();
@PostMapping(value = "user")
public String testFeignPost();
}
@FeignClient 注解表示当前是一个 Feign的客户端,value 属性是对应的服务名称,也就是需要调用哪个服务的接口,path 就是接口中 URI 统一的前缀。
- AdminFeignController
package com.pky.spring.cloud.web.admin.feign.controller;
import com.pky.spring.cloud.web.admin.feign.service.AdminService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping(value = "feign")
public class AdminFeignController {
@Autowired
AdminService adminService;
@GetMapping(value = "")
public String testFeign(){
return adminService.testFeign();
}
@GetMapping(value = "test_post")
public String testFeignPost(){
return adminService.testFeignPost();
}
}
浏览器输入 http://localhost:9701/feign/ ,显示 “hello, I’m service admin from port :9601”,证明调用成功。
4 自定义 Feign 的配置
4.1 日志配置
有时候我们遇到 bug,比如接口调用哪个失败、参数没收到等问题,或者想看看调用性能,就需要配置 Feign 的日志了,一次让 Feign 把请求信息输出出来。
- 定义一个配置类,如下:
package com.pky.spring.cloud.web.admin.feign.config;
import feign.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FeignConfiguration {
/**
* 日志级别
* @return
*/
@Bean
Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
}
- 日志级别源码
public static enum Level {
NONE, // 不输出日志
BASIC, // 只输出请求方法的 URL 和响应的状态码以及接口执行的时间
HEADERS, // 将 BASIC 信息和请求头信息输出
FULL; // 输出完整的请求信息
private Level() {
}
}
- 配置类建好后,需要在 Feign Client 中的 @FeignClient 注解中指定使用的配置类,如下:
package com.pky.spring.cloud.web.admin.feign.service;
import com.pky.spring.cloud.web.admin.feign.config.FeignConfiguration;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
@FeignClient(value = "admin-provider", path = "/admin", configuration = FeignConfiguration.class)
public interface AdminService {
@GetMapping(value = "")
public String testFeign();
@PostMapping(value = "user")
public String testFeignPost();
}
- 还需要在配置文件中配置输出的信息,application.yml 增加如下配置:
# 日志
logging:
level:
com:
pky:
spring:
cloud : DEBUG
- 通过 Feign 调用接口,可以在控制台看到如下输出的调用信息
[AdminService#testFeign] ---> GET http://admin-provider/admin HTTP/1.1
[AdminService#testFeign] ---> END HTTP (0-byte body)
[AdminService#testFeign] <--- HTTP/1.1 200 (4ms)
[AdminService#testFeign] content-length: 40
[AdminService#testFeign] content-type: text/plain;charset=UTF-8
[AdminService#testFeign] date: Fri, 09 Aug 2019 06:18:45 GMT
[AdminService#testFeign]
[AdminService#testFeign] hello, I'm service admin from port :9601
[AdminService#testFeign] <--- END HTTP (40-byte body)
4.2 Basic 认证配置
通常我们调用的接口都是有权限控制的,很多时候可能认证的值是通过参数去传递的,还有就是通过请求头去传递认证信息,比如 Basic 认证方式。在 Feign 中我们可以直接配置 Basic 认证,如下代码所示:
package com.pky.spring.cloud.web.admin.feign.config;
import feign.Logger;
import feign.auth.BasicAuthRequestInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FeignConfiguration {
/**
* 日志级别
* @return
*/
@Bean
Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
/**
* Basic 认证配置
* @return
*/
@Bean
public BasicAuthRequestInterceptor basicAuthRequestInterceptor() {
return new BasicAuthRequestInterceptor("pky", "123");
}
}
或者你可以自定义属于自己的认证方式,其实就是定义一个请求拦截器。在请求之前做认证操作,然后往请求头中设置认证之后的信息。通过实现 RequestInterceptor 接口来自定义认证方式,代码如下:
package com.pky.spring.cloud.web.admin.feign.config;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FeignBasicAuthRequestInterceptor implements RequestInterceptor {
public FeignBasicAuthRequestInterceptor() {
}
@Override
public void apply(RequestTemplate requestTemplate) {
// 业务逻辑
}
}
然后我们将配置改成我们自定义的就可以了,这样当 Feign 去请求接口的时候,每次请求之前都会进入 FeignBasicAuthRequestInterceptor 的 apply 方法中,在其里面就可以做属于自己的逻辑了,还需要在 FeignConfiguration 类中实例化 FeignBasicAuthRequestInterceptor ,如下
package config;
import com.pky.spring.cloud.web.admin.feign.config.FeignBasicAuthRequestInterceptor;
import feign.Logger;
import feign.auth.BasicAuthRequestInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FeignConfiguration {
@Bean
public FeignBasicAuthRequestInterceptor basicAuthRequestInterceptor(){
return new FeignBasicAuthRequestInterceptor();
}
}
4.3 超时时间配置
通过 Options 可以配置连接超时时间和读取超时时间,Options 的第一个参数是连接超时时间(ms),默认值是 10 * 1000;第第二个是读取超时时间(ms),默认值是 60 * 1000,如下代码所示
package com.pky.spring.cloud.web.admin.feign.config;
import feign.Logger;
import feign.Request;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FeignConfiguration {
/**
* 超时配置
* @return
*/
@Bean
public Request.Options options() {
return new Request.Options(5000, 10000);
}
}