文章目录
一、介绍
声明性REST客户端:Feign
Feign是一个声明式的伪Http客户端,它使得写Http客户端变得更简单。使用Feign,只需要创建一个接口并注解。它具有可插拔的注解特性,可使用Feign 注解和JAX-RS注解。Feign支持可插拔的编码器和解码器。
Feign默认集成了Ribbon,并和Eureka结合,默认实现了负载均衡的效果。
- Feign 采用的是基于接口的注解
- Feign 整合了ribbon,具有负载均衡的能力
- Feign整合了Hystrix,具有熔断的能力
编程式实现
需要以具体代码表达在哪里(where)做什么(what),如何实现(how)
声明式实现
只需要声明在哪里(where )做什么(what),而无需关心如何实现(how)
注意,使用Feign就不再使用Ribbon,所以把Ribbon的依赖和@LoadBalance注解删除
二、使用Feign
1.引入pom依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2.@EnableFeignClients
User服务启动类加注解,开启Feign
3.@FeignClient
使用Feign,不再使用Rest调用,就是正常的Controller调用Service.
具体的Feign的功能在Service中实现
Controller
@Autowired
UserService userService;
@GetMapping("/callDept")
public String callDept(){
String msg = "访问Dept服务";
return userService.callDept();
}
Service
注意:DEPT是我们在application.yml配置文件中配置的项目名。而且Dept服务的两个节点的项目名都叫dept
,只是端口号不同。
spring:
application:
name: dept
@FeignClient("DEPT")
public interface UserService {
@GetMapping("/dept/called")
String callDept() ;
}
服务被调用到,并且负载均衡轮询访问。
Bug 参数为[text/plain] 无法转化为json
方式零:
直接将返回类型修改为String。
方式一:
@GetMapping(value = "/dept/called",produces = "application/json;charset=UTF-8")
方式二:创建自定义解析类
public class MyMessageConverter extends MappingJackson2HttpMessageConverter {
public MyMessageConverter(){
List<MediaType> mediaTypes = new ArrayList<>();
mediaTypes.add(MediaType.TEXT_PLAIN);
setSupportedMediaTypes(mediaTypes);
}
}
方式三:配置类中注入自定义解析类
@Configuration // 有了该注解,该类就相当于是applicationContext.xml
public class ConfigBean {
// 解决返回参数为[text/plain] 无法转化为json
@Bean
public Decoder feignDecoder(){
MyMessageConverter myMessageConverter = new MyMessageConverter();
// Java8的lambda表达式。 ->
ObjectFactory<HttpMessageConverters> objectFactory = () -> new HttpMessageConverters(myMessageConverter);
return new SpringDecoder(objectFactory);
}
}
使用Feign带参调用服务-GET
UserController
UserService
使用Feign带参调用服务-POST
UserController
UserService
完整代码
YML配置文件
server:
port: 8001 #服务端口
eureka:
instance:
hostname: user8001
instance-id: user8001
prefer-ip-address: true
client:
service-url:
defaultZone: http://localhost:7000/eureka
spring:
application:
name: user8001
server:
port: 8002 #服务端口
eureka:
instance:
hostname: dept8002
instance-id: dept8002
prefer-ip-address: true
client:
service-url:
defaultZone: http://localhost:7000/eureka
spring:
application:
name: dept
server:
port: 8003 #服务端口
eureka:
instance:
hostname: dept8003
instance-id: dept8003
prefer-ip-address: true
client:
service-url:
defaultZone: http://localhost:7000/eureka
spring:
application:
name: dept
UserController
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
RestTemplate restTemplate;
@Autowired
UserService userService;
@GetMapping("/callDept")
public String callDept(){
String msg = "访问Dept服务";
System.out.println(msg);
return userService.callDept();
}
@GetMapping("/callDeptById1")
public String callDeptById1(@RequestParam String id){
String msg = "GET请求 表单形式";
System.out.println(msg);
return userService.callDeptAndParam(id);
}
@GetMapping("/callDeptById2/{id}")
public String callDeptById2(@PathVariable("id") String id){
String msg = "Get 路径带参";
System.out.println(msg);
return userService.callDeptAndParam2(id);
}
@PostMapping
public String callDeptPost(@RequestBody Map<String,String> map){
String msg = "POST JSON";
System.out.println(msg);
return userService.callDeptPost(map);
}
}
UserService
@FeignClient("DEPT")
public interface UserService {
@GetMapping(value = "/dept/called",produces = "application/json;charset=UTF-8")
String callDept() ;
/**
* 使用Fegin 访问 带参 GET请求 表单形式
* @param id
* @return
*/
@GetMapping(value = "/dept/called2")
String callDeptAndParam(@RequestParam("id") String id);
/**
* 以路径请求方式吓携带参数 Get 路径带参
* @param id
* @return
*/
@GetMapping(value = "/dept/called/{id}")
String callDeptAndParam2(@PathVariable("id") String id);
@PostMapping(value ="/dept/beCalledPost")
String callDeptPost(@RequestBody Map<String, String> map);
}
DeptController1
@RestController
@RequestMapping("/dept")
public class DeptController {
@GetMapping("/called")
public Object beCall() {
System.out.println("dept GET 无参 : 被访问了");
return "{\"code\":\"8002\"}";
}
@GetMapping("/called/{id}")
public Object beCallById(@PathVariable("id") String id) {
System.out.println("dept GET 带参 表单形式 : 被访问了");
return "{\"code\":\"8002\",\"id\":\""+id+"\"}";
}
@GetMapping("/called2")
public Object beCallById2(@RequestParam("id") String id) {
System.out.println("dept GET 带参 路径形式: 被访问了");
return "{\"code\":\"8002\",\"id\":\""+id+"\"}";
}
@PostMapping("/beCalledPost")
public Object beCalledPost(@RequestBody Map<String,String> map){
System.out.println("dept POST 带参 : 被访问了");
return "{\"code\":\"8002\",\"id\":\""+map.get("id")+"\",\"name\":\""+map.get("name")+"\"}";
}
}
DeptController2
@RestController
@RequestMapping("/dept")
public class DeptController {
@GetMapping("/called")
public Object beCall() {
System.out.println("dept GET 无参 : 被访问了");
return "{\"code\":\"8003\"}";
}
@GetMapping("/called/{id}")
public Object beCallById(@PathVariable("id") String id) {
System.out.println("dept GET 带参 表单形式 : 被访问了");
return "{\"code\":\"8003\",\"id\":\""+id+"\"}";
}
@GetMapping("/called2")
public Object beCallById2(@RequestParam("id") String id) {
System.out.println("dept GET 带参 路径形式: 被访问了");
return "{\"code\":\"8003\",\"id\":\""+id+"\"}";
}
@PostMapping("/beCalledPost")
public Object beCalledPost(@RequestBody Map<String,String> map){
System.out.println("dept POST 带参 : 被访问了");
return "{\"code\":\"8003\",\"id\":\""+map.get("id")+"\",\"name\":\""+map.get("name")+"\"}";
}
}
[Gitee仓库代码](https://gitee.com/L1692312138/spring-cloud_-ribbon_-fegin)
![在这里插入图片描述](https://img-blog.csdnimg.cn/20201106153739792.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0RyZWFtc0FyY2hpdGVjdHM=,size_16,color_FFFFFF,t_70#pic_center)