SpringCloudOpenFeign (服务调⽤)
1.定义
Feign是⼀个声明式的Web服务客户端,是⾯向接⼝编程的。也就是说使⽤Feign,只需要创建⼀个接⼝并使⽤注解⽅式配置它,就可以完成对微服务提供⽅的接⼝绑定。
OpenFeign对feign进⾏进⼀步的封装,添加了springmvc的⼀些功能,更加强⼤。
在使⽤RestTemplate时,每次调⽤服务都需要指定服务的具体路径,当在多个地⽅同时使⽤时要写多次,显得代码冗余也难以维护,⽽openfeign就可以避免这种操作。
2.项⽬实战
2.1基础环境搭建
这⾥使⽤consul作为服务注册中⼼。
1)创建⼀个maven⼯程名为cloud-open-feign-demo,删除src⽬录
2)在pom中导⼊依赖,对SpringBoot和SpringCloud 版本进⾏锁定
<properties>
<spring.boot.version>2.2.2.RELEASE</spring.boot.version>
<spring.cloud.version>Hoxton.SR1</spring.cloud.version>
<lombok.version>1.16.18</lombok.version>
</properties>
<!-- 依赖管理,⽗⼯程锁定版本-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring.boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring.cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
2.2搭建公共模块
1)新建maven⼦模块(common-api),导⼊依赖
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
2)创建实体对象
ity;
import lombok.Data;
@Data
public class User {
private String name;
private String username;
private Integer age;
}
2.3搭建服务提供者
1)新建maven⼦模块(cloud-provider8001),导⼊依赖
<dependencies>
<!--web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
2)新建启动类ProviderMain8001并添加注解
s.cloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; @SpringBootApplication
@EnableDiscoveryClient
public class ProviderMain8001 {
public static void main(String[] args) {
SpringApplication.run(ProviderMain8001.class, args);
}
}
3)配置l
server:
port: 8001
spring:
application:
name: cloud-consul-provider
cloud:
consul:
host: localhost
port: 8500
discovery:
service-name: ${spring.application.name}
4)新建controller 接⼝
ller;
ity.User;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
@RestController
public class UserController {
@Value("${server.port}")
private String port;
@GetMapping("/user/get")
public String get() {
return"我是服务提供者,端⼝:" + port;
}
@GetMapping("/user/getParam")
public String getParam(@RequestParam("name") String name) {
return"我是服务提供者,参数:" + name + ",端⼝:" + port;
}
@PostMapping("/user/postParam")
public String postParam(@RequestParam("username") String username) {
return"我是服务提供者,参数:" + username + ",端⼝:" + port;
}
@PostMapping("/user/add")
public String addUser(@RequestBody User user) {
return"我是服务提供者,参数:" + String() + ",端⼝:" + port;
}
}
这⾥的接⼝并没有在类上使⽤@RequestMapping注解,⽽是把接⼝路径都写在⽅法上⾯,那么在服务调⽤⽅进⾏映射时直接复制其⽅法名即可,不需要⽅法体。
5)启动服务,可看到已注册到consul。
6)根据服务提供者ProviderMain8001,再创建ProviderMain8002.
2.4搭建服务消费者
1)新建maven⼦模块(cloud-consumer80),导⼊依赖
<dependencies>
<!--web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--feign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId&s.cloud</groupId>
<artifactId>common-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
2)新建启动类ConsumerMain80并添加注解
s.cloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
class ConsumerMain80 {
public static void main(String[] args) {
SpringApplication.run(ConsumerMain80.class, args);
}
}
要在启动类上启⽤Feign客户端。
3)配置l
server:
port: 80
spring:
application:
name: cloud-consul-consumer
cloud:
consul:
host: localhost
port: 8500
discovery:
service-name: ${spring.application.name}
3)创建服务接⼝UserServiceClient,对于服务提供者接⼝。需要添加注解@FeiginClient,指定微服务的名称
s.cloud.service;
ity.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
//指定微服务名称
@FeignClient(value = "cloud-consul-provider")
public interface UserServiceClient {
@GetMapping("/user/get")
String get();
@GetMapping("/user/getParam")
String getParam(@RequestParam("name") String name);
@PostMapping("/user/postParam")
String postParam(@RequestParam("username") String username);
@PostMapping("/user/add")
String addUser(@RequestBody User user);
}
注意:
必须使⽤注解@FeignClient指定服务提供⽅的服务名称
在编写接⼝映射时,可直接复制服务提供⽅的⽅法名等信息
get请求传递参数时,要使⽤@RequestParam注解,其value是参数的名字,需与服务提供者端保持⼀致 post请求传递参数时,当参数是对象时使⽤@RequestBody,当参数不是对象时需使⽤@RequestParam注解4)创建controller接⼝,将UserServiceClient 注⼊使⽤
ller;
ity.User;
s.cloud.service.UserServiceClient;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
@RestController
@RequestMapping("/consumer")
public class TestController {
@Resource
private UserServiceClient userServiceClient;
@GetMapping("/get")
public String get() {
();
}
@GetMapping("/param")
public String getParam(String name) {
Param(name);
}
@PostMapping("/post")
public String postParam(String username) {
return userServiceClient.postParam(username);
}
@PostMapping("/add")
public String addUser(@RequestBody User user) {
return userServiceClient.addUser(user);
}
}
5)启动测试。先启动服务提供者集,再启动服务消费者,对四个接⼝进⾏测试,服务均可正常调⽤。
另外对其中⼀个接⼝进⾏多次刷新,会发现服务提供者集是遵循轮询机制。原因是openfeignl默认已引⼊了Ribbon ,可提供负载均衡策略。
2.5超时控制
为了体现服务快速响应的特点,Feign默认等待1秒,超过后报错。也就是说Feigin客户端只等待⼀秒,若服务端处理过程超过⼀秒,会导致客户端会出错,故需设置超时时间,避免出现这样的情况。
1)情景重现
为了看到这种效果,可在服务提供者的接⼝中设置线程阻塞,让其响应时间超过1S。这⾥以8001为例,修改UserController的get()⽅法:
spring framework版本@GetMapping("/user/get")
public String get() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return"我是服务提供者,端⼝:" + port;
}
截图:
重启后测试这个接⼝,消费者控制台报错:
2)配置超时时间
在客户端(服务消费者80)的yml进⾏配置即可。配置有两种⽅式:
1)⽅式⼀:设置Ribbon的负载超时时间
#设置ribbon的负载超时时间,单位都是ms
ribbon:
#指的是建⽴连接所⽤的时间,适⽤于⽹络状况正常的情况下,两端连接所⽤的时间
ReadTimeout: 5000
#指的是建⽴连接后从服务器读取到可⽤资源所⽤的时间
ConnectTimeout: 5000
2)⽅式⼆:设置feign 的超时时间
feign:
client:
config:
#指定全局
default:
#连接超时时间
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论