SpringCloud组件openfeign的使用
注意:本次实现必须使用到nacos的注册中心
gitee:springcloud组件openfeign使用
个人建议:配置的方式学习openfeign组件,这样更加容易看懂
目录结构
maven依赖
父工程(springcloud-openfeign)依赖
<parent>
<artifactId>spring-boot-starter-parent</artifactId>
<groupId>org.springframework.boot</groupId>
<version>2.1.13.RELEASE</version>
</parent>
<dependencyManagement>
<dependencies>
<!-- Spring Dependencies -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.1.13.RELEASE</version>
<scope>import</scope>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Greenwich.SR6</version>
<scope>import</scope>
<type>pom</type>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.1.4.RELEASE</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
子模块【openfeign客户端】
(client-openfeign-annotation【注解方式】,client-openfeign-config【配置方式】)依赖
<dependencies>
<!-- web依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- nacos注册中心依赖 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- openfeign依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>
子模块【openfeign服务端】
(product-openfeign,stock-openfeign)
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
openfeign服务端
product-openfeign服务
目录结构
maven依赖
子模块【openfeign服务端】
配置文件(application.yaml)
server:
port: 8230 #模拟时需要进行通过idea配置之后开启多个服务
spring:
application:
name: product-openfeign
cloud:
nacos:
discovery:
namespace: 2ce93c25-dd8f-4972-8350-73833228e108
username: nacos
password: nacos
server-addr: 192.168.153.199:8848
controller
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author 黔程似景
* @description
* @date 2022/9/29 6:28
* @blame 黔程似景
**/
@RestController
public class ProductController {
@Value("${server.port}")
private String port;
@GetMapping("/product")
public String product() throws InterruptedException {
return "服务: " + port;
}
/**
* 请求feign超时
*/
@GetMapping("/timeout")
public String timeout() throws InterruptedException {
Thread.sleep(10000);
return "服务: " + port;
}
}
启动类
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author 黔程似景
* @description 启动类
* @date 2022/9/29 6:27
* @blame 黔程似景
**/
@SpringBootApplication
public class ProductOpenFeignApplication {
public static void main(String[] args) {
SpringApplication.run(ProductOpenFeignApplication.class, args);
}
}
stock-openfeign服务
目录结构
maven依赖
子模块【openfeign服务端】
配置文件(application.yaml)
server:
port: 8220
spring:
application:
name: stock-openfeign
cloud:
nacos:
discovery:
namespace: 2ce93c25-dd8f-4972-8350-73833228e108
username: nacos
password: nacos
server-addr: 192.168.153.199:8848
controller
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author 黔程似景
* @description stock服务提供接口
* @date 2022/9/27 6:57
* @blame 黔程似景
**/
@RestController
@RequestMapping("/stock")
public class StockController {
@Value("${server.port}")
private String port;
/**
* 库存修改
*/
@GetMapping("/goods")
public String goods() {
System.out.println("商品库存修改");
return "服务:" + port ;
}
@GetMapping("/{id}")
public String findOrderByUserId(@PathVariable("id") String id) {
System.out.println("根据用户Id查询商品");
return "服务:" + port + " id为:" + id;
}
}
启动类
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author 黔程似景
* @description feign调用提供端
* @date 2022/9/27 6:56
* @blame 黔程似景
**/
@SpringBootApplication
public class StockOpenFeignApplication {
public static void main(String[] args) {
SpringApplication.run(StockOpenFeignApplication.class , args);
}
}
openfeign客户端
client-openfeign-annotation【注解注入方式】
目录结构
maven依赖
子模块【openfeign客户端】
配置文件(application.yaml)
server:
port: 8210
spring:
application:
name: client-openfeign-annotation
cloud:
nacos:
discovery:
namespace: 2ce93c25-dd8f-4972-8350-73833228e108
username: nacos
password: nacos
server-addr: 192.168.153.199:8848
# ribbon 默认为懒加载模式,即用的时候才会去加载,需要设置启动加载配置如下
ribbon:
eager-load:
# 开启ribbon饥饿加载
enabled: true
# 配置mall‐user使用ribbon饥饿加载,多个使用逗号分隔
clients: stock-openfeign,product-openfeign
# 使用配置的形式进行设置负载均衡策略
stock-openfeign:
ribbon:
# 轮询策略
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule
product-openfeign:
ribbon:
# 轮询策略
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
# 服务日志配置(因为默认spring日志是info,会阻挡feign日志输出)
logging:
level:
com.qq.openfeign.client: debug
拦截器(interceptor)
import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author 黔程似景
* @description
* @date 2022/9/29 6:58
* @blame 黔程似景
**/
public class CustomFeignInterceptor implements RequestInterceptor {
Logger logger = LoggerFactory.getLogger(this.getClass());
@Override
public void apply(RequestTemplate requestTemplate) {
logger.info("---------------feign拦截器使用------------");
String url = requestTemplate.url();
if("/1".equals(url)){
logger.info("url地址:" + url);
requestTemplate.uri("/9");
}
}
}
配置类(config)
import feign.Contract;
import feign.Logger;
import feign.Request;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author 黔程似景
* @description OpenFeign相关配置
* @date 2022/9/28 6:52
* @blame 黔程似景
**/
@Configuration
public class OpenFeignConfig {
/**
* 配置打印feign调用接口的日志
*/
@Bean
public Logger.Level feignLoggerLevel(){
//full配置比较特殊,需要将spring默认的日志级别info改为debug,否则看不到效果
return Logger.Level.FULL;
}
/**
* 修改契约配置,支持Feign原生的注解,老版本是不支持springmvc注解的,此处仅作演示,项目中用到的是fegin的注解时,需要切换
*/
@Bean
public Contract feignContract(){
return new Contract.Default();
}
/**
* 设置请求feign超时时间
*/
@Bean
public Request.Options options() {
return new Request.Options(5000, 1000);
}
/**
* 进行注入拦截器使用
*/
@Bean
public CustomFeignInterceptor feignAuthRequestInterceptor(){
return new CustomFeignInterceptor();
}
}
openfeign调用类(service)
ProductFeignService(product服务)
import feign.RequestLine;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
/**
* @author 黔程似景
* @description feign调用product服务
* @date 2022/9/28 22:49
* @blame 黔程似景
*
* @FeignClient(name = "product-openfeign" ,path = "/xx" )
* 1. name : 服务名
* 2. path : 服务下某个controller类上面的注解@RequestMapping("/xx")的value参数
*
*
**/
@FeignClient(name = "product-openfeign" )
public interface ProductFeignService {
@GetMapping("/product")
@RequestLine("GET /product") //早期feign不支持springMvc注解
String product();
@GetMapping("/timeout")
@RequestLine("GET /timeout") //早期feign不支持springMvc注解
String timeout();
}
StockFeignService(stock服务)
import feign.Param;
import feign.RequestLine;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
/**
* @author 黔程似景
* @description feign调用stock服务
* @date 2022/9/28 22:49
* @blame 黔程似景
*
* @FeignClient(name = "product-openfeign" ,path = "/stock" )
* 1. name : 服务名
* 2. path : 服务下某个controller类上面的注解@RequestMapping("/stock")的value参数
*
**/
@FeignClient(name = "stock-openfeign" , path = "/stock")
public interface StockFeignService {
#@GetMapping("/goods")
@RequestLine("GET /goods")
String goods();
#@GetMapping("/{id}")
@RequestLine("GET /{id}") # feign早期版本不支持springmvc注解,@Param("id")=@PathVariable("id")
String findOrderByUserId(@Param("id") String id);
}
controller
import com.qq.openfeign.client.service.ProductFeignService;
import com.qq.openfeign.client.service.StockFeignService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author 黔程似景
* @description openfeign调用客户端接口
* @date 2022/9/27 7:08
* @blame 黔程似景
**/
@RestController
@RequestMapping("/client")
public class ClientController {
@Autowired
private StockFeignService stockFeignService;
@Autowired
private ProductFeignService productFeignService;
@GetMapping("/demo")
public String demo() {
System.out.println("----------------------进行负载均衡调用-----------------");
return "stock" + stockFeignService.goods() + "\n product" + productFeignService.product();
}
/**
* 拦截器使用
*/
@GetMapping("/interceptor/{id}")
public String interceptor(@PathVariable("id") String id){
System.out.println("----------------------进行负载均衡调用-----------------");
return stockFeignService.findOrderByUserId(id);
}
/**
* 请求feign超时
*/
@GetMapping("/timeout")
public String timeout(){
return productFeignService.timeout();
}
}
启动类
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
/**
* @author 黔程似景
* @description 启动类
* @date 2022/9/28 22:46
* @blame 黔程似景
**/
@SpringBootApplication
@EnableFeignClients
public class ClientOpenFeignApplication {
public static void main(String[] args) {
SpringApplication.run(ClientOpenFeignApplication.class , args);
}
}
启动测试
注意:启动2个stock-openfeign服务,2个product-openfeign服务,外加当前类
client-openfeign-config【配置方式实现】
目录结构
maven依赖
子模块【openfeign客户端】
配置文件(application.yaml)
server:
port: 8211
spring:
application:
name: client-openfeign-config
cloud:
nacos:
discovery:
namespace: 2ce93c25-dd8f-4972-8350-73833228e108
username: nacos
password: nacos
server-addr: 192.168.153.199:8848
# ribbon 默认为懒加载模式,即用的时候才会去加载,需要设置启动加载配置如下
ribbon:
eager-load:
# 开启ribbon饥饿加载
enabled: true
# 配置mall‐user使用ribbon饥饿加载,多个使用逗号分隔
clients: stock-openfeign,product-openfeign
# 使用配置的形式进行设定负载均衡策略
stock-openfeign:
ribbon:
# 轮询
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule
# 使用配置的形式进行设定负载均衡策略
product-openfeign:
ribbon:
# 轮询
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
logging:
level:
com.qq.openfeign.client: debug
# feign日志级别配置
feign:
client:
config:
stock-openfeign: # 负载均衡的服务名
loggerLevel: FULL
contract: feign.Contract.Default # 配置方式使用原生注解
connectTimeout: 5000 # 配置方式设置feign请求连接时间
readTimeout: 3000 # 配置方式设置feign请求读取时间 # 请求处理超时时间,默认5s
requestInterceptors[0]: com.qq.openfeign.client.interceptor.CustomFeignInterceptor
product-openfeign:
loggerLevel: FULL
#contract: feign.Contract.Default # 配置方式使用原生注解
connectTimeout: 5000 # 配置方式设置feign请求连接时间
readTimeout: 3000 # 配置方式设置feign请求读取时间
拦截器(interceptor)
import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author 黔程似景
* @description
* @date 2022/9/29 6:58
* @blame 黔程似景
**/
public class CustomFeignInterceptor implements RequestInterceptor {
Logger logger = LoggerFactory.getLogger(this.getClass());
@Override
public void apply(RequestTemplate requestTemplate) {
logger.info("---------------feign拦截器使用------------");
String url = requestTemplate.url();
if("/1".equals(url)){
logger.info("url地址:" + url);
requestTemplate.uri("/9");
}
}
}
openfeign调用类(service)
ProductFeignService(product服务)
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
/**
* @author 黔程似景
* @description feign调用product服务
* @date 2022/9/28 22:49
* @blame 黔程似景
*
* @FeignClient(name = "product-openfeign" ,path = "/xx" )
* 1. name : 服务名
* 2. path : 服务下某个controller类上面的注解@RequestMapping("/xx")的value参数
*
*
**/
@FeignClient(name = "product-openfeign" )
public interface ProductFeignService {
@GetMapping("/product")
String product();
@GetMapping("/timeout")
String timeout();
}
StockFeignService(stock服务)
import feign.Param;
import feign.RequestLine;
import org.springframework.cloud.openfeign.FeignClient;
/**
* @author 黔程似景
* @description feign调用stock服务
* @date 2022/9/28 22:49
* @blame 黔程似景
*
* @FeignClient(name = "product-openfeign" ,path = "/stock" )
* 1. name : 服务名
* 2. path : 服务下某个controller类上面的注解@RequestMapping("/stock")的value参数
**/
@FeignClient(name = "stock-openfeign" , path = "/stock")
public interface StockFeignService {
@RequestLine("GET /goods")
String goods();
@RequestLine("GET /{id}")
String findOrderByUserId(@Param("id") String id);
}
controller
import com.qq.openfeign.client.service.ProductFeignService;
import com.qq.openfeign.client.service.StockFeignService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author 黔程似景
* @description openfeign调用客户端
* @date 2022/9/27 7:08
* @blame 黔程似景
**/
@RestController
@RequestMapping("/client")
public class ClientController {
@Autowired
private StockFeignService stockFeignService;
@Autowired
private ProductFeignService productFeignService;
@GetMapping("/demo")
public String demo() {
System.out.println("进行负载均衡调用-----------------");
return "stock" + stockFeignService.goods() + "\n product" + productFeignService.product();
}
/**
* 拦截器使用
*/
@GetMapping("/interceptor/{id}")
public String interceptor(@PathVariable("id") String id){
System.out.println("----------------------进行负载均衡调用-----------------");
return stockFeignService.findOrderByUserId(id);
}
/**
* 请求feign超时
*/
@GetMapping("/timeout")
public String timeout(){
return productFeignService.timeout();
}
}
启动类
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
/**
* @author 黔程似景
* @description 启动类
* @date 2022/9/28 22:46
* @blame 黔程似景
**/
@SpringBootApplication
@EnableFeignClients
public class ClientOpenFeignApplication {
public static void main(String[] args) {
SpringApplication.run(ClientOpenFeignApplication.class , args);
}
}
启动测试
注意:启动2个stock-openfeign服务,2个product-openfeign服务,外加当前类