内容简介:上一篇文章,讲述了如何通过创建一个在
上一篇文章,讲述了如何通过 RestTemplate
配合 Ribbon
去消费服务。 Feign
是一个 声明式
的 HTTP
伪客户端
,提供 面向接口
的 HTTP
客户端调用
编程。本文进一步讲如何通过 Feign
去消费服务。
-
Feign只需要创建一个 接口 并提供 注解 即可调用。 -
Feign具有 可插拔 的注解特性,可使用Feign注解 和JAX-RS注解 。 -
Feign支持 可插拔 的 编码器 和 解码器 。 -
Feign默认集成了Ribbon,可以和Eureka结合使用,默认实现了 负载均衡 的效果。
正文
1. 创建服务契约模块
创建一个 service-contract
的项目 Module
,创建完成后的 pom.xml
如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>io.ostenant.github.springcloud</groupId>
<artifactId>service-contract</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>service-contract</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>io.ostenant.github.springcloud</groupId>
<artifactId>service-contract</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
复制代码
在 service-contract
中定义 业务接口
和相关的 DTO
对象如下:
User.java
public class User implements Serializable {
private String name;
private int age;
public User() {
}
public User(String name, int age) {
this.name = name;
this.age = age;
}
public void getName() {
return this.name;
}
public String setName() {
this.name = name;
}
public int getAge() {
return this.age;
}
public void setAge(int age) {
this.age = age;
}
}
复制代码
UserContract.java
UserContract
定义了 User
的所有行为,是一个使用 @FeignClient
注解标记的 声明式服务接口
。其中, @FeignClient
的 value
指定的是 服务提供者
的 服务名称
。
@FeignClient("service-provider")
public interface UserContract {
@PostMapping("/user")
void add(@RequestBody User user);
@GetMapping("/user/{name}")
User findByName(@PathVariable String name);
@GetMapping("/users")
List<User> findAll();
}
复制代码
对于 服务提供者
而言,需要实现 UserContract
接口的方法;对于 服务消费者
而言,可以直接注入 UserContract
作为 客户端桩
使用。
2. 创建服务提供者
创建一个 service-provider
的项目 Module
,创建完成后引入 服务契约模块
的依赖, pom.xml
如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>io.ostenant.github.springcloud</groupId>
<artifactId>service-provider</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>service-provider</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Dalston.SR1</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>io.ostenant.github.springcloud</groupId>
<artifactId>service-contract</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
复制代码
通过 注解
@EnableEurekaClient
表明自己是一个 Eureka Client
。
@SpringBootApplication
@EnableEurekaClient
@RestController
public class ServiceProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceProviderApplication.class, args);
}
}
复制代码
创建一个类 UserService
,实现 UserContract
接口的具体业务,对外提供 User
相关的 HTTP
的服务。
@RestController
public class UserService implements UserContract {
private static final Set<User> userSet = new HashSet<>();
static {
userSet.add(new User("Alex", 28));
userSet.add(new User("Lambert", 32));
userSet.add(new User("Diouf", 30));
}
@Override
public void add(@RequestBody User user) {
userSet.add(user);
}
@Override
public User findByName(@PathVariable String name) {
return userSet.stream().filter(user -> {
return user.getName().equals(name);
}).findFirst();
}
@Override
public List<User> findAll() {
return new ArrayList<>(userSet);
}
}
复制代码
在 配置文件
中注明的 服务注册中心
的地址, application.yml
配置文件如下:
spring:
active:
profiles: sp1 # sp2
---
spring:
profiles: sp1
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
server:
port: 8770
spring:
application:
name: service-provider
---
spring:
profiles: sp2
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
server:
port: 8771
spring:
application:
name: service-provider
复制代码
分别以 spring.profiles.active=sp1
和 spring.profiles.active=sp2
作为 Spring Boot
的 启动命令参数
,在 端口号
8770
和 8771
启动 2
个 服务提供者
实例。
3. 创建服务消费者
新建一个项目 Module
,取名为 service-consumer
,在它的 pom
文件中引入 Feign
的 起步依赖
和 服务契约模块
,代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>io.ostenant.github.springcloud</groupId>
<artifactId>service-consumer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>service-consumer</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Dalston.SR1</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>io.ostenant.github.springcloud</groupId>
<artifactId>service-contract</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
复制代码
在项目的配置文件 application.yml
文件,指定 应用名称
为 service-consumer
, 端口号
为 8772
, 服务注册地址
为 http://localhost:8761/eureka/
,代码如下:
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
server:
port: 8772
spring:
application:
name: service-feign
复制代码
在应用的启动类 ServiceConsumerApplication
上加上 @EnableFeignClients
注解开启 Feign
的功能。
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class ServiceConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceConsumerApplication.class, args);
}
}
复制代码
定义一个 UserController
控制器,用于调用 服务提供者
提供的服务并 响应
前端。
@RestController
public class UserController {
@Autowired
private UserContract userContract;
@PostMapping("/user")
public void add(@RequestBody User user) {
userContract.add(user);
}
@GetMapping("/user/{name}")
public User findByName(@PathVariable String name) {
return userContract.findByName(name);
}
@GetMapping("/users")
public List<User> findAll() {
return userContract.findAll();
}
}
复制代码
在 控制层
UserController
引入 Feign
接口,通过 @FeignClient
( 服务名称
),来指定调用的是哪个 服务
。
启动 服务消费者
应用,访问 http://localhost:8772/users
测试 服务消费者
的访问连通性,响应内容为:
[
{
"name": "Alex",
"age": 28
},
{
"name": "Lambert",
"age": 32
},
{
"name": "Diouf",
"age": 30
}
]
复制代码
4. Feign的源码实现过程
总的来说, Feign
的 源码实现
过程如下:
-
首先通过
@EnableFeignClients注解开启FeignClient的功能。只有这个 注解 存在,才会在程序启动时 启动@FeignClient注解 的 包扫描 。 -
服务提供者实现基于
Feign的 契约接口 ,并在 契约接口 上面加上@FeignClient注解。 -
服务消费者启动后,会进行 包扫描 操作,扫描所有的
@FeignClient的 注解 的类,并将这些信息注入Spring上下文中。 -
当 接口 的方法被调用时,通过
JDK的 代理 来生成具体的RequestTemplate模板对象 。 -
根据
RequestTemplate再生成HTTP请求的Request对象。 -
Request对象交给Client去处理,其中Client内嵌的 网络请求框架 可以是HTTPURLConnection、HttpClient和OkHttp。 -
最后
Client被封装到LoadBalanceClient类,这个类结合Ribbon完成 负载均衡 功能。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 基于 Pub/Sub 的同步 RRPC 调用实战
- 实战使用 Arthas 排查生产问题:实例方法接口调用
- Python实战---制作专属有声小说(调用百度语音合成接口)
- Jaeger-分布式调用链跟踪系统理论与实战
- Spring Cloud实战系列(二) - 客户端调用Rest + Ribbon
- FGC实战:如何用Idea揪出开源组件调用System.gc导致频繁FGC
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Beginning Apache Struts
Arnold Doray / Apress / 2006-02-20 / USD 44.99
Beginning Apache Struts will provide you a working knowledge of Apache Struts 1.2. This book is ideal for you Java programmers who have some JSP familiarity, but little or no prior experience with Ser......一起来看看 《Beginning Apache Struts》 这本书的介绍吧!