feign漫谈
feign的简单使用。
文章目录
- 什么是feign
- 准备工作
- 三.如何使用
- 3.1 定义pom文件
- 3.2 定义配置文件及启动类注解
- 3.3 定义feign接口
什么是feign
远程调用框架
准备工作
需要nacos环境:
涉及到feign调用,就没法抛开注册中心,接下来我们使用主流的nacos作为注册中心进行搭建本地环境。具体参见之前的nacos系列:https://blog.csdn.net/imVainiycos/article/details/122917022
三.如何使用
3.1 定义pom文件
- 新建一个maven项目作为父工程
父工程的pom文件如下:
<?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>
<groupId>com.vainycos</groupId>
<artifactId>demo-spring-cloud</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<!-- 预留三个模块 -->
<module>core</module>
<module>customer</module>
<module>supermarket</module>
</modules>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<springboot.version>2.2.5.RELEASE</springboot.version>
<spring.cloud.version>Hoxton.SR3</spring.cloud.version>
<spring.cloud.alibaba.version>2.2.1.RELEASE</spring.cloud.alibaba.version>
</properties>
<dependencyManagement>
<dependencies>
<!--支持Spring Boot 2.1.X-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${springboot.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>
<!-- alibaba-cloud -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring.cloud.alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!--服务调用-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
</dependency>
<!--注册中心-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
</project>
- 新建三个子模块,模拟一个超市购物行为和结账会员身份识别场景,分别是:
- core - 核心模块,feign接口层或者其他核心类
- customer - 会员模块,依赖[core]模块,通过core模块的feign统一调用[supermarket]服务
- supermarket - 超市模块,依赖[core]模块,通过core模块的feign统一调用[customer]服务
core模块的pom文件:
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.vainycos</groupId>
<artifactId>demo-spring-cloud</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.vainycos</groupId>
<artifactId>core</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>core</name>
<description>core</description>
<properties>
<java.version>8</java.version>
</properties>
<dependencies>
<!-- spring-boot-starter-web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
customer模块的pom文件:
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.vainycos</groupId>
<artifactId>demo-spring-cloud</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<groupId>com.vainycos</groupId>
<artifactId>customer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>customer</name>
<description>customer</description>
<properties>
<java.version>8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.vainycos</groupId>
<artifactId>core</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
supermarket模块的pom文件:
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.vainycos</groupId>
<artifactId>demo-spring-cloud</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<groupId>com.example</groupId>
<artifactId>supermarket</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>supermarket</name>
<description>supermarket</description>
<properties>
<java.version>8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.vainycos</groupId>
<artifactId>core</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
3.2 定义配置文件及启动类注解
假设你本地的nacos已经启动完成了,启动端口为默认的8848。
两个模块的配置均大同小异,这里以customer模块为例。
这里需要注意由于使用微服务的配置需要优先加载,所以我们不在原来的application.yaml或者application.yml上进行配置,而是新建一个bootstrap.yml文件进行配置,配置内容如下:
server:
# 定义另一个模块的启动端口为8082
port: 8081
spring:
application:
# 定义另一个模块的值为market
name: customer
cloud:
nacos:
discovery:
server-addr: localhost:8848
在启动类CustomerApplication上加注解@EnableDiscoveryClient以及@EnableFeignClients(basePackageClasses = {CustomerApplication.class, CoreApplication.class}),这里需要依赖core模块,所以把core的启动类也注入。
@EnableDiscoveryClient
@EnableFeignClients(basePackageClasses = {CustomerApplication.class, CoreApplication.class})
@SpringBootApplication
public class CustomerApplication {
public static void main(String[] args) {
SpringApplication.run(CustomerApplication.class, args);
}
}
3.3 定义feign接口
首先我们在customer模块定义一个接口,根据id查询客户信息:
@RequestMapping("/customer")
@RestController
public class CustomerController {
@Autowired
private MarketService marketService;
@GetMapping("/getUser/{id}")
public String getById(@PathVariable("id") Integer id){
return "获取id=" + id + "的用户";
}
}
调用本服务进行测试,访问/customer/getUser/1,结果如下表示通过:
我们到core模块下定义一个feign接口CustomerService,在类名上加注解@FeignClient(name = “customer”),该注解name的值需要注意与调用服务方配置文件重的application.name保持一致,比如这里是customer:
完整的feign接口定义如下,这里需要注意每个入参都需要定义入参格式,比如这里是路径参数即加上@PathVariable,其他的还有@RequestParameter,@RequestBody等等,并且@GetMapping的请求地址需要与对应模块的请求地址保持一致:
package com.vainycos.core.feign.customer;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@FeignClient(name = "customer")
public interface CustomerService {
@GetMapping("/customer/getUser/{id}")
String getCustomerById(@PathVariable("id") Integer id);
}
这个时候我们模拟一个场景,即在supermarket模块结账的时候需要调用customer模块获取会员信息。
在supermarket模块中定义controller,把上面的feign接口注入进来即可调用:
package com.example.supermarket.controller;
import com.vainycos.core.feign.customer.CustomerService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author: Vainycos
* @description
* @date: 2023/1/16 13:30
*/
@RequestMapping("/market")
@RestController
public class MarketController {
@Autowired
private CustomerService customerService;
@GetMapping("/buy")
public String order(String things, Integer id){
String customerById = customerService.getCustomerById(id);
return customerById + "购买了" +things;
}
}
访问/market/buy?things=苹果电脑&id=1,结果如下:
到这里,完整的feign调用链路就已经搭建完成了。
同理,我们也可以在supermarket定义获取商品列表的服务,然后提供给customer调用:
package com.example.supermarket.controller;
import com.vainycos.core.feign.customer.CustomerService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author: Vainycos
* @description
* @date: 2023/1/16 13:30
*/
@RequestMapping("/market")
@RestController
public class MarketController {
@Autowired
private CustomerService customerService;
/**
* 获取商品列表
* @return
*/
@GetMapping("/listMarket")
public String listMarket(){
return "啤酒,瓜子,花生米";
}
@GetMapping("/buy")
public String order(String things, Integer id){
// 调用feign接口
String customerById = customerService.getCustomerById(id);
return customerById + "购买了" +things;
}
}
然后在core模块下定义feign接口
package com.vainycos.core.feign.supermarket;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
/**
* @author: Vainycos
* @description
* @date: 2023/1/16 16:18
*/
@FeignClient(name = "market")
public interface MarketService {
@GetMapping("/market/listMarket")
String listMarket();
}
最后在customer模块中注入feign接口MarketService进行使用:
package com.vainycos.customer.controller;
import com.vainycos.core.feign.supermarket.MarketService;
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: Vainycos
* @description
* @date: 2023/1/16 13:27
*/
@RequestMapping("/customer")
@RestController
public class CustomerController {
@Autowired
private MarketService marketService;
@GetMapping("/listMarket/{id}")
public String listMarket(@PathVariable("id") Integer id){
// 调用feign接口
String goods = marketService.listMarket();
return "用户id=" + id + "查询商品列表:" + goods;
}
@GetMapping("/getUser/{id}")
public String getById(@PathVariable("id") Integer id){
return "获取id=" + id + "的用户";
}
}
访问/customer/listMarket/1,结果如下:
参考资料:
- Feign的使用
- 什么是Feign?
- 【微服务】分布式组件 Nacos 结合 Feign 的使用