public class UrlService {
public static final String SERVER_URL = "http://localhost:8080/";
}
Hello World
public interface HelloClient {
@RequestLine("GET /hello")
String sayHello();
}
HelloClient hello = Feign.builder()
.target(HelloClient.class, UrlService.SERVER_URL);
编码器和解码器 encoder decoder
public interface PersonClient {
@RequestLine("GET /person/{personId}")
Person findById(@Param("personId") Integer personId);
@RequestLine("POST /person/create")
@Headers("Content-Type: application/json")
String createPerson(Person person);
}
PersonClient personService = Feign.builder()
.decoder(new GsonDecoder())
.encoder(new GsonEncoder())
.target(PersonClient.class, UrlService.SERVER_URL);
- 自定义编码器
import feign.codec.Decoder;
public class PersonDecoder implements Decoder {
public Object decode(Response response, Type type) throws IOException, DecodeException, FeignException {
// ...
}
}
PersonClient personService = Feign.builder()
//.decoder(new GsonDecoder())
.decoder(new PersonDecoder())
.target(PersonClient.class, UrlService.SERVER_URL);
客户端 client
feign默认使用HttpClient
客户端发送请求。
可以使用其他客户端
PersonClient personClient = Feign.builder()
.decoder(new GsonDecoder())
.client(new OkHttpClient())
.target(PersonClient.class, UrlService.SERVER_URL);
也可以自定义客户端
import feign.Client;
import feign.Request;
import feign.Response;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import java.io.IOException;
import java.net.URI;
import java.util.Collection;
import java.util.HashMap;
public class MyFeignClient implements Client {
/**
* 将Feign的Request实例,转换为HttpClient的HttpRequestBase,再使用CloseableHttpClient来执行请求;
* 得到响应的HttpResponse实例后,再转换为Feign的Reponse实例返回。
*/
@Override
public Response execute(Request request, Request.Options options) throws IOException {
try {
// 创建一个默认的客户端
CloseableHttpClient httpclient = HttpClients.createDefault();
// 获取调用的HTTP方法
final String method = request.httpMethod().name();
// 创建一个HttpClient的HttpRequest
HttpRequestBase httpRequest = new HttpRequestBase() {
@Override
public String getMethod() {
return method;
}
};
// 设置请求地址
httpRequest.setURI(new URI(request.url()));
// 执行请求,获取响应
HttpResponse httpResponse = httpclient.execute(httpRequest);
// 获取响应的主体内容
byte[] body = EntityUtils.toByteArray(httpResponse.getEntity());
// 将HttpClient的响应对象转换为Feign的Response
Response response = Response.builder()
.body(body)
.headers(new HashMap<String, Collection<String>>())
.status(httpResponse.getStatusLine().getStatusCode())
.request(request)
.build();
return response;
} catch (Exception e) {
throw new IOException(e);
}
}
}
PersonClient personClient = Feign.builder()
.decoder(new GsonDecoder())
.client(new MyFeignClient())
.target(PersonClient.class, UrlService.SERVER_URL);
注解翻译器 contract
import javax.ws.rs.GET;
import javax.ws.rs.Path;
public interface JaxRsClient {
@GET
@Path("/hello")
String rsHello();
}
JaxRsClient rsClient = Feign.builder()
.contract(new JAXRSContract())
.target(JaxRsClient.class, UrlService.SERVER_URL);
自定义注解翻译器
@Target(METHOD)
@Retention(RUNTIME)
public @interface MyUrl {
// 定义url与method属性
String url();
String method();
}
import feign.Contract;
import feign.MethodMetadata;
import feign.Request;
import morning.cat.annotation.MyUrl;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
/**
* 一个Contract实际上承担的是一个翻译的作用,将第三方(或者自定义)注解的作用告诉Feign。
* 在Spring Cloud中,也实现了Spring的Contract,可以在接口中使用@RequestMapping注解,读者在学习Spring Cloud整合Feign时,见到使用@RequestMapping修饰的接口,就可以明白其中的原理。
*/
public class MyContract extends Contract.BaseContract {
@Override
protected void processAnnotationOnClass(MethodMetadata data, Class<?> clz) {
}
/**
* 用于处理方法级的注解
*/
@Override
protected void processAnnotationOnMethod(MethodMetadata data,
Annotation annotation, Method method) {
// 是MyUrl注解才进行处理
if (MyUrl.class.isInstance(annotation)) {
// 获取注解的实例
MyUrl myUrlAnn = method.getAnnotation(MyUrl.class);
// 获取配置的HTTP方法
String httpMethod = myUrlAnn.method();
// 获取服务的url
String url = myUrlAnn.url();
// 将值设置到模板中
data.template().method(Request.HttpMethod.valueOf(httpMethod));
data.template().uri(url);
}
}
@Override
protected boolean processAnnotationsOnParameter(MethodMetadata data,
Annotation[] annotations, int paramIndex) {
return false;
}
}
MyUrlClient client = Feign.builder()
.contract(new MyContract())
.target(MyUrlClient.class, UrlService.SERVER_URL);
依赖
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-core</artifactId>
<version>${feign.version}</version>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-gson</artifactId>
<version>${feign.version}</version>
</dependency>
<!-- Feign对JAXRS的支持 -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-jaxrs</artifactId>
<version>${feign.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.github.openfeign/feign-okhttp -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
<version>${feign.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.github.openfeign/feign-httpclient -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
<version>${feign.version}</version>
</dependency>
<!-- JAXRS -->
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>jsr311-api</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.2</version>
</dependency>