SpringCloud(四)学习笔记之Feign
Feign是一个声明式的Web服务客户端,可帮助我们更加便捷、优雅地调用HTTP API
Feign可以与Eureka和Ribbon组合使用以支持负载均衡
一、构建Eureka Server
【基于第二章节创建的Eureka Server】
二、构建Eureka Client提供者集群项目
【基于第三章节构建的Eureka Client提供者集群项目】
1:提供者集群项目中创建controller
mhb-cloud-producer mhb-cloud-producer-extend
【创建UserVo对象】com\applesnt\vo\UserVo.java
package com.applesnt.vo;
import lombok.Data;
@Data
public class UserVo {
private String user_id;
private String user_name;
private String code;
public UserVo(String user_id, String user_name, String code) {
this.user_id = user_id;
this.user_name = user_name;
this.code = code;
}
public UserVo() {
}
}
mhb-cloud-producer :9904
mhb-cloud-producer-extend:9905
【创建Controller】com\applesnt\controller\FeignProducerController.java
package com.applesnt.controller;
import com.applesnt.vo.UserVo;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
@RestController
@RequestMapping("/producer")
public class FeignProducerController {
/*返回传递过来的id
* 请求路径:http://localhost:9904/producer/get/123
* */
@GetMapping("/get/{id}")
public String getId(@PathVariable("id") String id){
System.out.println("-----"+id);
return "我是提供者 端口是9904 传递的参数= "+id;
}
/*参数为id 返回user对象
* 请求路径:http://localhost:9904/producer/getuserbyid/123
* */
@GetMapping("/getuserbyid/{id}")
public UserVo getUserById(@PathVariable("id") String id){
UserVo userVo = new UserVo();
userVo.setUser_id(id);
userVo.setUser_name("applesnt");
userVo.setCode("9904");
return userVo;
}
/*
* 返回user对象
* 访问路径:http://localhost:9904/producer/getuser2?id=123&name=lisi
* */
@GetMapping("/getuser2")
public UserVo getUser2(@RequestParam("id") String id,
@RequestParam("name") String name){
UserVo userVo = new UserVo();
userVo.setUser_id(id);
userVo.setUser_name(name);
userVo.setCode("9904");
return userVo;
}
/*
* 返回user对象
* 访问路径:http://localhost:9904/producer/getuser3?user_id=123&user_name=lisi
* */
@GetMapping("/getuser3")
public UserVo getUser3(UserVo userVo){
userVo.setUser_id(userVo.getUser_id());
userVo.setUser_name(userVo.getUser_name());
userVo.setCode("9904");
return userVo;
}
/*参数uservo 返回UserVo
* postman body--raw(选择json格式)
* 数据格式:{"user_id":"123","user_name":"zhangsan"}
* */
@PostMapping("/getuser")
public UserVo getUser(@RequestBody UserVo userVo){
return userVo;
}
/*返回UserVo集合
* 请求路径:http://localhost:9904/producer/getlist/
* */
@GetMapping("/getlist")
public List<UserVo> getUserList(){
List<UserVo> voList = new ArrayList<>();
UserVo userVo1 = new UserVo("1","zhangsan","9904");
UserVo userVo2 = new UserVo("2","lisi","9904");
UserVo userVo3 = new UserVo("3","wangwu","9904");
voList.add(userVo1);voList.add(userVo2);voList.add(userVo3);
return voList;
}
}
三、创建Eureka消费者项目(基于Feign)
mhb-cloud-consumer-Feign:【端口 8801】
1:pom文件
<!--eureka客户端环境支持-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--feign环境支持-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2:application.yml文件
debug: false
spring:
application:
name: mhb-cloud-consumer-feign #每一个微服务必须有这个应用名称
server:
port: 8801 #端口
eureka:
instance:
appname: consumer-feign #eureka application的名称
prefer-ip-address: true #开启ip显示eureka的主机服务
#eureka仪表盘的Instances格式
instance-id: ${spring.application.name}:${spring.cloud.client.ip-address}:${server.port}
client:
service-url:
defaultZone: http://admin:123456@eureka1.com:8762/eureka/,http://admin:123456@eureka2.com:8762/eureka/,http://admin:123456@eureka3.com:8763/eureka/
#从eureka服务器注册表中获取注册表信息的时间间隔,默认30s
registry-fetch-interval-seconds: 30
#客户端发送变化同步到eureka服务器的时间间隔 默认30s
instance-info-replication-interval-seconds: 30
#询问eureka服务url信息的变化的间隔时间 默认300s
eureka-service-url-poll-interval-seconds: 300
#最初同步到eureka服务器的时间 默认40s
initial-instance-info-replication-interval-seconds: 40
#注册表是否压缩
g-zip-content: true
#eureka等待超时时间 默认是5s
eureka-server-connect-timeout-seconds: 5
#eureka等待读取时间 默认是8s
eureka-server-read-timeout-seconds: 8
#eureka客户端允许的所有eureka服务器连接的总数 默认200
eureka-server-total-connections: 200
3:启动类中开启Feign支持
@@EnableEurekaClient
@EnableFeignClients
package com.applesnt;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.feign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients //开启feign支持
public class MhbCloudConsumerFeignApplication {
public static void main(String[] args) {
SpringApplication.run(MhbCloudConsumerFeignApplication.class, args);
}
}
4:构建Feign远程调用接口
@FeignClient(name = "mhb-cloud-producer",configuration = FeignClientsConfiguration.class)
com\applesnt\service\FeignClientService.java
package com.applesnt.service;
import com.applesnt.vo.UserVo;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.cloud.openfeign.FeignClientsConfiguration;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/*
name:提供者的服务名称
configuration:使用默认配置类 FeignClientsConfiguration
默认配置支持springmvc注解
*/
@FeignClient(name = "mhb-cloud-producer",configuration = FeignClientsConfiguration.class)
public interface FeignClientService {
/*value要写全路径
* PathVariable一定要指定value值
* */
@GetMapping("/producer/get/{id}")
public String getId(@PathVariable("id") String id);
@GetMapping("/producer/getuserbyid/{id}")
public UserVo getUserById(@PathVariable("id") String id);
@GetMapping("/producer/getuser2")
public UserVo getUser2(@RequestParam("id") String id,
@RequestParam("name") String name);
/*
* 如果传入复杂(vo类型)参数时 不支持get请求 远程调用对象必须要用post请求
* 所以getUser3是调用失败的
* */
@GetMapping("/producer/getuser3")
public UserVo getUser3(UserVo userVo);
/*POST请求 如果是复杂对象 可以使用@RequestBody 也可以不使用*/
@PostMapping("/producer/getuser")
public UserVo getUser(@RequestBody UserVo userVo);
@GetMapping("/producer/getlist")
public List<UserVo> getUserList();
}
5:构建远程调用controller
【构建UserVo对象】com\applesnt\vo\UserVo.java
package com.applesnt.vo;
import lombok.Data;
@Data
public class UserVo {
private String user_id;
private String user_name;
private String code;
public UserVo(String user_id, String user_name, String code) {
this.user_id = user_id;
this.user_name = user_name;
this.code = code;
}
public UserVo() {
}
}
【构建远程调用Controller】com\applesnt\controller\FeignConsumerController.java
package com.applesnt.controller;
import com.applesnt.service.FeignClientService;
import com.applesnt.vo.UserVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/feign")
@Slf4j
public class FeignConsumerController {
@Autowired/*feign远程服务接口注入*/
private FeignClientService feignClientservice;
@GetMapping("/get/{id}")
//http://127.0.0.1:8801/feign/get/123
public String getId(@PathVariable("id") String id){
String reutrnStr = feignClientservice.getId(id);
log.info("feign调用 = {}",reutrnStr);
return reutrnStr;
}
@GetMapping("/getuserbyid/{id}")
//http://127.0.0.1:8801/feign/getuserbyid/123
public UserVo getUserById(@PathVariable("id") String id){
UserVo userVo = feignClientservice.getUserById("123");
log.info("feign调用 = {}",userVo);
return userVo;
}
@GetMapping("/getuser2")
//http://127.0.0.1:8801/feign/getuser2?id=123&name=zhangsan
public UserVo getUser2(@RequestParam(name = "id",required = false) String id,
@RequestParam("name") String name){
UserVo userVo = feignClientservice.getUser2(id,name);
log.info("feign调用 = {}",userVo);
return userVo;
}
@GetMapping("/getuser3")
//http://127.0.0.1:8801/feign/getuser3?user_id=123&user_name=zhangsan
public UserVo getUser3(UserVo userVo){
/*feign调用-会报错,不支持get远程调用*/
UserVo uVo = feignClientservice.getUser3(userVo);
log.info("feign调用 = {}",uVo);
return uVo;
}
@PostMapping("/getuser")
//http://127.0.0.1:8801/feign/getuser【要用postman模拟post请求】
public UserVo getUser(@RequestBody UserVo userVo){
UserVo uVo = feignClientservice.getUser(userVo);
log.info("feign调用 = {}",uVo);
return uVo;
}
@GetMapping("/getlist")
//http://127.0.0.1:8801/feign/getlist
public List<UserVo> getUserList(){
List<UserVo> list = feignClientservice.getUserList();
log.info("feign调用 = {}",list);
return list;
}
}
6:Feign远程调用测试
分别启动Eureka服务集群、mhb-cloud-consumer-feign、mhb-cloud-producer、mhb-cloud-producer-extend六个服务
http://127.0.0.1:8801/feign/getuser2?id=123&name=zhangsan
第一次访问:
第二次访问:
四、Feign调用非微服务
创建远程调用service接口
@FeignClient(name = "xxxx",url = "http://localhost:8761")
com\applesnt\service\FeignClientService2.java
package com.applesnt.service;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.*;
/*不写configuration属性 默认使用FeignClientsConfiguration
* 默认配置支持springmvc注解
* */
@FeignClient(name = "xxxx",url = "http://localhost:8761")
public interface FeignClientService2 {
@GetMapping(value = "/eureka/apps")
public String getapp();
}
在FeignConsumerController中追加远程调用方法:
@Autowired/*feign远程服务接口注入(非微服务)*/
private FeignClientService2 feignClientService2;
/*访问非微服务*/
//http://127.0.0.1:8801/feign/getapp
@GetMapping("/getapp")
public String getapp(){
String reutrnStr = feignClientService2.getapp();
return reutrnStr;
}
五、Feign日志配置
由于Feign默认不开启日志,所有我们要创建一个配置类用于覆盖默认配置
com\applesnt\config\FeignLogConfiguration.java
package com.applesnt.config;
import feign.Logger;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FeignLogConfiguration {
@Bean
Logger.Level feignLoggerLevel(){
return Logger.Level.FULL;
}
}
2:在feign的远程调用service接口中,配置上FeignLogConfiguration类
@FeignClient(name = "mhb-cloud-producer",configuration = FeignLogConfiguration.class)
3:在application.yml中开启service接口的日志输出
logging:
level:
com.applesnt.service.FeignClientService: debug
4:日志输出
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用