第一个Feign程序
编码器:如果服务端只接受JSON字符串格式/XML,那么我们客户端使用的是对象。在这种情况下,我们可以使用编码器将对象转换成JSON字符串/XML。
解码器:将服务端的响应结果对象,转换为客户端的对象。这个时候就需要用到解码器。
1. Feign被集成到SpringCloud Netflix模块,当Eureka,Ribbon集成的时候呢,Feign就具备了负载均衡的功能。Feign本身使用就很简便,再加上与SpringCloud的整合,将很大程度上降低我们开发的工作量。
2. 它是Github上面的一个开源项目,目的是为了简化WebService客户端的开发,在使用Feign的时候 可以使用注解来修饰接口,被修饰的接口就具有了访问webservice的能力,这些注解呢 可以使用Feign的自带注解,也可以支持使用第三方的注解。Feign还支持插件式的编码器和解码器,使用者可以通过这些特性,对请求和响应进行封装和解析。
Feign会更加的面向对象,下面我们使用Feign来对比一下CXF。在这之前我们需要准备对外提供接口。
如果没有接口等项目的朋友,可以参照前几章的“SpringCloud 中使用 Ribbon(默认轮询规则 + 自定义规则)”搭建(只搭建服务器与服务提供者即可)
这里我们一次把依赖CXF、Feign的依赖全部引入:pom.xml
<dependencies>
<!-- CXF 依赖 -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-core</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-rs-client</artifactId>
<version>3.1.0</version>
</dependency>
<!-- Feign 依赖 -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-core</artifactId>
<version>9.5.0</version>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-gson</artifactId>
<version>9.5.0</version>
</dependency>
<!-- 如果请求格式用XML的时候,需要加入以下XML依赖 -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-jaxb</artifactId>
<version>9.5.0</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.2.8</version>
</dependency>
</dependencies>
下面我们编写一个CXF客户端,进行测试:CxfClient.java
public class CxfClient {
public static void main(String[] args) throws IOException {
// 创建 WebClient
WebClient client = WebClient.create("http://localhost:9090/getPoliceById/123");
// 获取响应
Response response = client.get();
// 获取响应内容
InputStream is = (InputStream) response.getEntity();
String content = IOUtils.readStringFromStream(is);
// 打印结果
System.out.println("请求结果:" + content);
}
}
乱码的问题不用管,我们就看 WebClient.create 方法中的url,url多的话,维护起来也麻烦,而且还需要对流进行操作。。。接下来,我们编写一个Feign程序,与CXF进行一下对比
在文章的一开始,提到了 Feign 程序会更加的面向对象,所以我们先创建一个实体类,用来接收结果对象:Police.java
public class Police {
private String id;// 警察编号,用来保存用户输入的参数
private String url;// 处理请求的服务器url
private String message;// 提示信息
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
其次,我们创建一个接口类:FeignService.java
public interface FeignService {
@RequestLine("GET /getPolice")
public String getPolice();
@RequestLine("GET /getPolice")
public Police getPoliceObj();
@RequestLine("GET /getPoliceById/{id}")
public String getPoliceById(@Param("id") String id);
/**
* 发送JSON对象,返回字符串
* @param police
* @return
*/
@RequestLine("POST /createPolice")
@Headers("Content-Type: application/json")// 这里要指定请求类型
public String createPolice(Police police);
/**
* 发送XML对象,返回字符串
* @return
*/
@RequestLine("POST /createXmlPolice")
@Headers("Content-Type: application/xml")// 这里要指定请求类型
public Police createXmlPolice(Police police);
}
最后,我们再创建一个测试类,查看结果:TestMain.java
public static void main(String[] args) {
/**
* 根据ID获取派出警察,返回JSON字符串
*/
FeignService client_1 = Feign.builder().target(FeignService.class, "http://localhost:9090");
String policeStr = client_1.getPolice();
System.out.println("返回JSON字符串:"+policeStr);
String policeByIdStr = client_1.getPoliceById("123");
System.out.println("根据ID获取派出警察,返回JSON字符串:"+policeByIdStr);
/**
* 返回警察对象
*/
FeignService client_2 = Feign.builder().decoder(new GsonDecoder()).target(FeignService.class, "http://localhost:9090");
Police police = client_2.getPoliceObj();
System.out.println("返回警察对象:");
System.out.println(" url:"+police.getUrl());
System.out.println(" message:"+police.getMessage());
/**
* 发送JSON对象,返回字符串
*/
FeignService client_3 = Feign.builder().encoder(new GsonEncoder()).target(FeignService.class, "http://localhost:9090");
Police police_json = new Police();
police_json.setMessage("你好");
String createResult = client_3.createPolice(police_json);
System.out.println("发送JSON格式参数,返回字符串:"+createResult);
/**
* 发送XML对象,返回字符串
* 使用XML进行发送与接收时,实体类需要使用注解:
* 类上注解:@XmlRootElement
* 字段注解:@XmlElement
* get方法使用注解:@XmlTransient
*/
JAXBContextFactory encoder = new JAXBContextFactory.Builder().build();
FeignService client_4 = Feign.builder()
.encoder(new JAXBEncoder(encoder))
.decoder(new JAXBDecoder(encoder))
.target(FeignService.class, "http://localhost:9090");
Police police_xml = new Police();
police_xml.setMessage("你好");
Police policeResult = client_4.createXmlPolice(police_xml);
System.out.println("发送XML格式参数,返回字符串:"+policeResult.getMessage());
}
但是如果向接口传入xml格式值,那接口应该怎么定义呢?
// 接收xml,返回xml
@RequestMapping(value="/createXmlPolice", method=RequestMethod.POST, produces=MediaType.APPLICATION_XML_VALUE, consumes=MediaType.APPLICATION_XML_VALUE)
public String createXmlPolice(@RequestBody Police police){
return "<police><message>"+police.getMessage()+"</message></police>";
}
OK,这样子就可以传递xml格式的参数了。。。那么下面贴一下以上main方法中的所有执行结果
额外再说一下,Feign的客服端 也是可插拔的,,下面教大家如何实现自定义客户端,并访问
首先需要自定义一个客户端,需要实现Feign的Client接口:MyClient.java
public class MyClient implements Client {
@Override
public Response execute(Request request, Options options) throws IOException {
try {
// 创建一个默认的客户端
CloseableHttpClient httpClient = HttpClients.createDefault();
// 获取调用的HTTP方法
final String method = request.method();
// 创建一个HttpClient的Request
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 feignResponse = Response.builder()
.body(body)
.headers(new HashMap<String, Collection<String>>())
.status(httpResponse.getStatusLine().getStatusCode())
.build();
return feignResponse;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
编写一个测试main方法:
/**
* 使用可插拔式的自定义client客户端,进行请求访问
*/
FeignService client_5 = Feign.builder().client(new MyClient()).target(FeignService.class, "http://localhost:9090");
String policeStr = client_5.getPolice();
System.out.println("返回JSON字符串:"+policeStr);
下面贴上运行结果