疯狂Spring Cloud连载(10)——Rest客户端Feign介绍

本文节选自《疯狂Spring Cloud微服务架构实战》html

京东购买地址:https://item.jd.com/12256011.htmljava

当当网购买地址:http://product.dangdang.com/25201393.htmlgit

Spring Cloud教学视频:https://my.oschina.net/JavaLaw/blog/1552993github

Spring Cloud电子书:https://my.oschina.net/JavaLaw/blog/1570383web

本文要点spring

             REST客户端apache

        Spring Cloud集群中,各个角色的通讯基于REST服务,所以在调用服务时,就不可避免的须要使用REST服务的请求客户端。前面的章节中使用了Spring自带的RestTemplate,RestTemplate使用的是HttpClient发送请求。本章中,将介绍另外一个REST客户端:Feign。服务器

10 REST客户端Feign介绍

        在学习Feign前,先了解REST客户端,本小节将简单地讲述Apache CXF与Restlet这两款Web Service框架,并使用这两个框架来编写REST客户端,最后再编写一个Feign的Hello World例子。经过此过程,让你们能够对Feign有一个初步的印象。如已经掌握这两个REST框架,可直接到后面章节学习Feign。架构

        本章的各个客户端,将会访问8080端口的“/person/{personId}”和“/hello”这两个服务中的一个,服务端项目使用“spring-boot-starter-web”进行搭建,本小节对应的服务端项目目录为:codes\05\5.1\rest-server。负载均衡

10.1 使用CXF调用REST服务

        CXF是目前一个较为流行的Web Service框架,是Apache下的一个开源项目。使用CXF能够发布和调用各类协议的服务,包括SOAP协议、XML/HTTP等,当前CXF已经对REST风格的Web Service提供支持,能够发布或调用REST风格的Web Service。因为CXF能够与Spring进行整合使用而且配置简单,所以获得许多开发者的青睐,而笔者以往所在公司的大部分项目,均使用CXF来发布和调用Web Service,本章所使用的CXF版本为3.1.10,Maven中加入如下依赖:

<dependency>
			<groupId>org.apache.cxf</groupId>
			<artifactId>cxf-core</artifactId>
			<version>3.1.10</version>
		</dependency>
		<dependency>
			<groupId>org.apache.cxf</groupId>
			<artifactId>cxf-rt-rs-client</artifactId>
			<version>3.1.10</version>
		</dependency>

        编写代码请求/person/{personId}服务,请见代码清单5-1。

        代码清单5-1:codes\05\5.1\rest-client\src\main\java\org\crazyit\cloud\CxfClient.java

package org.crazyit.cloud;

import java.io.InputStream;

import javax.ws.rs.core.Response;

import org.apache.cxf.helpers.IOUtils;
import org.apache.cxf.jaxrs.client.WebClient;

/**
 * CXF访问客户端
 * @author 杨恩雄
 *
 */
public class CxfClient {

	public static void main(String[] args) throws Exception {
		// 建立WebClient
		WebClient client = WebClient.create("http://localhost:8080/person/1");
		// 获取响应
		Response response = client.get();
		// 获取响应内容
		InputStream ent = (InputStream) response.getEntity();
		String content = IOUtils.readStringFromStream(ent);
		// 输出字符串
		System.out.println(content);
	}
}

        客户端中,使用了WebClient类发送请求,获取响应后读取输入流,获取服务返回的JSON字符串。,运行代码清单5-1,可看到返回的信息。

10.2 使用Restlet调用REST服务

        Restlet是一个轻量级的REST框架,使用它能够发布和调用REST风格的Web Service。本小节例子所使用的版本为2.3.10,Maven依赖以下:

<dependency>
			<groupId>org.restlet.jee</groupId>
			<artifactId>org.restlet</artifactId>
			<version>2.3.10</version>
		</dependency>
		<dependency>
			<groupId>org.restlet.jee</groupId>
			<artifactId>org.restlet.ext.jackson</artifactId>
			<version>2.3.10</version>
		</dependency>

        客户端实现请见代码清单5-2。

        代码清单5-2:codes\05\5.1\rest-client\src\main\java\org\crazyit\cloud\RestletClient.java

package org.crazyit.cloud;

import java.util.HashMap;
import java.util.Map;

import org.restlet.data.MediaType;
import org.restlet.ext.jackson.JacksonRepresentation;
import org.restlet.representation.Representation;
import org.restlet.resource.ClientResource;

/**
 * Restlet客户端
 * @author 杨恩雄
 *
 */
public class RestletClient {

	public static void main(String[] args) throws Exception {
		ClientResource client = new ClientResource(
				"http://localhost:8080/person/1");
		// 调用get方法,服务器发布的是GET
		Representation response = client.get(MediaType.APPLICATION_JSON);
		// 建立JacksonRepresentation实例,将响应转换为Map
		JacksonRepresentation jr = new JacksonRepresentation(response,
				HashMap.class);
		// 获取转换后的Map对象
		Map result = (HashMap) jr.getObject();
		// 输出结果
		System.out.println(result.get("id") + "-" + result.get("name") + "-"
				+ result.get("age") + "-" + result.get("message"));
	}
}

        代码清单5-2中使用Restlet的API较为简单,在此不过多赘述,但须要注意的是,在Maven中使用Restlet,要额外配置仓库地址,笔者成书时Apache官方仓库中,并无Restlet的包。在项目的pom.xml文件中增长如下配置:

<repositories>
		<repository>
			<id>maven-restlet</id>
			<name>Restlet repository</name>
			<url>http://maven.restlet.org</url>
		</repository>
	</repositories>

10.3 Feign框架介绍

        Feign是一个Github上一个开源项目,目的是为了简化Web Service客户端的开发。在使用Feign时,可使用注解来修饰接口,被注解修饰的接口具备访问Web Service的能力,这些注解中既包括了Feign自带的注解,也支持使用第三方的注解。除此以外,Feign还支持插件式的编码器和解码器,使用者能够经过该特性,对请求和响应进行不一样的封装与解析。

        Spring Cloud将Feign集成到netflix项目中,当与Eureka、Ribbon集成时,Feign就具备负载均衡的功能。Feign自己在使用上的简便性,加上与Spring Cloud的高度整合,使用该框架在Spring Cloud中调用集群服务,将会大大下降开发的工做量。

10.4 第一个Feign程序

        先使用Feign编写一个Hello World的客户端,访问服务端的“/hello”服务,获得返回的字符串。当前Spring Cloud所依赖的Feign版本为9.5.0,本章案例中的Feign也使用该版本。创建名称为“feign-client”的Maven项目,加入如下依赖:

<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>

        新建接口HelloClient,请见代码清单5-3。

        代码清单5-3:codes\05\5.1\feign-client\src\main\java\org\crazyit\cloud\HelloClient.java

package org.crazyit.cloud;

import feign.RequestLine;

/**
 * 客户端调用的服务接口
 * @author 杨恩雄
 *
 */
public interface HelloClient {

	  @RequestLine("GET /hello")
	  String sayHello();
}

        HelloClient表示一个服务接口,接口的“sayHello”方法中,使用了@RequestLine注解,表示使用GET方法,向“/hello”发送请求。接下来编写客户端的运行类,请见代码清单5-4。

代码清单5-4:codes\05\5.1\feign-client\src\main\java\org\crazyit\cloud\HelloMain.java

package org.crazyit.cloud;

import feign.Feign;
import feign.gson.GsonDecoder;

public class HelloMain {

	public static void main(String[] args) {
		// 调用Hello接口
		HelloClient hello = Feign.builder().target(HelloClient.class,
				"http://localhost:8080/");
		System.out.println(hello.getClass().getName());
		System.out.println(hello.sayHello());
	}
}

        运行类中,使用Feign建立HelloClient接口的实例,最后调用接口定义的方法。运行代码清单5-4,能够看到返回的“Hello World”字符串,可见接口已经被调用。熟悉AOP的朋友大概已经猜到,Feign实际上会帮咱们动态生成代理类。Feign使用的是JDK的动态代理,生成的代理类,会将请求的信息封装,交给feign.Client接口发送请求,而该接口的默认实现类,最终会使用java.net.HttpURLConnection来发送HTTP请求。

10.5 请求参数与返回对象

        本案例中有两个服务,另一个地址为“/person/{personId}”,须要传入参数而且返回JSON字符串,编写第二个Feign客户端,调用该服务。新建PersonClient服务类,定义调用接口并添加注解,请见代码清单5-5。

        代码清单5-5:codes\05\5.1\feign-client\src\main\java\org\crazyit\cloud\PersonClient.java

package org.crazyit.cloud;

import lombok.Data;
import lombok.NoArgsConstructor;
import feign.Param;
import feign.RequestLine;

/**
 * Person客户端服务类
 * @author 杨恩雄
 *
 */
public interface PersonClient {

	@RequestLine("GET /person/{personId}")
	Person findById(@Param("personId") Integer personId);
	
	@Data // 为全部属性加上setter和getter等方法
	class Person {
		Integer id;
		String name;
		Integer age;
		String message;
	}
}

        定义的接口名称为“findById”,参数为“personId”。须要注意的是,因为会返回Person实例,咱们在接口中定义了一个Person的类,为了减小代码量,使用了Lombok项目,使用了该项目的@Data注解。要使用Lombok,须要添加如下Maven依赖:

<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<version>1.16.18</version>
		</dependency>

        准备好提供服务的客户端类后,再编写运行类。运行类基本上与前面的HelloWorld相似,请见代码清单5-6。

        代码清单5-6:codes\05\5.1\feign-client\src\main\java\org\crazyit\cloud\PersonMain.java

package org.crazyit.cloud;

import org.crazyit.cloud.PersonClient.Person;

import feign.Feign;
import feign.gson.GsonDecoder;

/**
 * Person服务的运行主类
 * @author 杨恩雄
 *
 */
public class PersonMain {

	public static void main(String[] args) {
		PersonClient personService = Feign.builder()
				.decoder(new GsonDecoder())
				.target(PersonClient.class, "http://localhost:8080/");
		Person person = personService.findById(2);
		System.out.println(person.id);
		System.out.println(person.name);
		System.out.println(person.age);
		System.out.println(person.message);
	}
}

        调用Person服务的运行类中,添加了解码器的配置,GsonDecoder会将返回的JSON字符串,转换为接口方法返回的对象,关于解码器等内容,将在后面章节中讲述。运行代码清单5-6,能够看到最终的输出。

        本小节使用了CXF、Restlet、Feign来编写REST客户端,在编写客户端的过程当中,能够看到Feign的代码更加“面向对象”,至因而否更加简洁,则见仁见智。下面的章节,将深刻了解Feign的各项功能。

 

        本文节选自《疯狂Spring Cloud微服务架构实战》

        Spring Cloud教学视频:https://my.oschina.net/JavaLaw/blog/1552993

Spring Cloud电子书:https://my.oschina.net/JavaLaw/blog/1570383

本书代码共享地址:https://gitee.com/yangenxiong/SpringCloud

相关文章
相关标签/搜索