提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言
Springboot集成Feign遇到了很多问题,配置成功后决定记录一下,方便后续查看,如果同时能帮助到有需要的人,我将不胜欣喜!
提示:以下是本篇文章正文内容,下面案例可供参考
一、版本
Springboot 3.3.2
Spring Cloud Alibaba 2023.0.1.0
Feign 4.1.3
二、工程创建
1. 创建工程文件
初始配置如下:
2. 添加依赖
在项目的pom.xml文件中添加 Spring Cloud Alibaba 的依赖:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2023.0.1.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
3. 创建微服务
按照图片一步步创建两个微服务 order-service 和 user-service 即可
(1)创建 Module
(2)配置 Module
(3)最终的目录结构
(4)pom.xml 内容
- CloudNacos04 的 pom.xml
<?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>
<packaging>pom</packaging>
<modules>
<module>order-service</module>
<module>user-service</module>
</modules>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.abc</groupId>
<artifactId>CloudNacos04</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>CloudNacos04</name>
<description>Demo project for Spring Boot</description>
<url/>
<licenses>
<license/>
</licenses>
<developers>
<developer/>
</developers>
<scm>
<connection/>
<developerConnection/>
<tag/>
<url/>
</scm>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter-test</artifactId>
<version>3.0.3</version>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2023.0.1.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
- order-service 的 pom.xml
<?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">
<parent>
<artifactId>CloudNacos04</artifactId>
<groupId>com.abc</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>order-service</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
<dependencies>
<!--Nacos服务发现依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- SpringCloud Loadbalancer -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
<version>4.1.3</version>
</dependency>
</dependencies>
</project>
- user-service 的 pom.xml
<?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">
<parent>
<artifactId>CloudNacos04</artifactId>
<groupId>com.abc</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>user-service</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
</project>
记得配置完pom.xml文件一定要点右上角蓝色图标的 ”Load Maven change” 导入依赖
(5)配置application.yaml
order-service 和 user-service 两个微服务都需要配置yaml文件,如何配置参考图片(这里就是最基本的配置,不涉及nacos的共享配置)。
(6)具体功能实现的编码
目录结构如下:
- OrderMapper.java
package com.qmm.mapper;
import com.qmm.pojo.Order;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
@Mapper
public interface OrderMapper {
@Select("select * from tb_order where id = #{id}")
public Order findByID(int id);
}
- OrderServiceImpl.java
package com.qmm.service.impl;
import com.qmm.mapper.OrderMapper;
import com.qmm.pojo.Order;
import com.qmm.pojo.User;
import com.qmm.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
@Service
public class OrderServiceImpl implements OrderService {
@Autowired
OrderMapper orderMapper;
@Autowired
RestTemplate restTemplate;
@Override
public Order queryOrderById(int orderId) {
// 1. 查询订单
Order order = orderMapper.findByID(orderId);
// 2. 利用RestTemplate发起http请求
String url = "http://localhost:8082/user/" + order.getUserId();
User user = restTemplate.getForObject(url, User.class);
// 3. 封装user到order
order.setUser(user);
return order;
}
}
- OrderController.java
package com.qmm.controller;
import com.qmm.pojo.Order;
import com.qmm.service.OrderService;
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.RestController;
@RestController
public class OrderController {
@Autowired
OrderService orderService;
@GetMapping("/order/{id}")
public Order queryById(@PathVariable int id){
return orderService.queryOrderById(id);
}
}
- order-service 的启动类 OrderApplication.java
package com.qmm;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class,args);
}
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
- UserMapper.java
package com.qmm.mapper;
import com.qmm.pojo.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
@Mapper
public interface UserMapper {
@Select("select * from tb_user where id = #{id}")
public User findById(int id);
}
- UserServiceImpl.java
package com.qmm.service.impl;
import com.qmm.mapper.UserMapper;
import com.qmm.pojo.User;
import com.qmm.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl implements UserService {
@Autowired
UserMapper userMapper;
@Override
public User findById(int id) {
return userMapper.findById(id);
}
}
- UserController.java
package com.qmm.controller;
import com.qmm.pojo.User;
import com.qmm.service.UserService;
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.RestController;
@RestController
public class UserController {
@Autowired
UserService userService;
@GetMapping("/user/{id}")
public User findUserById(@PathVariable int id) {
return userService.findById(id);
}
}
- user-service 的启动类 UserApplication.java
package com.qmm;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class UserApplication {
public static void main(String[] args) {
SpringApplication.run(UserApplication.class, args);
}
}
- 实体类 User.java
package com.qmm.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Integer id;
private String username;
private String address;
}
- 实体类 Order.java
package com.qmm.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Order {
private Integer id;
private Integer price;
private String name;
private Integer num;
private Integer userId;
private User user;
}
4. 启动微服务
- 单机模式启动nacos,命令如下:
startup.cmd -m standalone
- 运行启动类 UserApplicaiton.java 和 OrderApplication.java
- 地址栏输入
localhost:8848/nacos
- 若在服务列表看到两个服务的信息,则说明注册成功
- 服务调用
5. Feign远程调用
使用Feign代替ResTemplate发送http请求
5.1 引入依赖
在order-service的pom.xml中添加如下依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>4.1.3</version>
</dependency>
一定要注意Spring Cloud Alibaba 与 Feign 的版本匹配
5.2 添加注解
在order-service的启动类添加注解 @EnableFeignClients
开启Feign功能
5.3 编写Feign客户端
package com.qmm.client;
import com.qmm.pojo.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
// 声明远程调用信息
@FeignClient("userservice") //指定服务名称
public interface UserClient {
@GetMapping("/user/{id}")
User findById(@PathVariable int id);
}
这个客户端主要是基于SpringMVC的注解来声明远程调用的信息,比如:
- 服务名称:userservice
- 请求方式:GET
- 请求路径:/user/{id}
- 请求参数:int id
- 返回值类型:User
这样,Feign就可以帮助我们发送http请求,无需自己使用RestTemplate来发送了。
5.4 利用Feign发送http请求
修改OrderServiceImpl.java:
package com.qmm.service.impl;
import com.qmm.client.UserClient;
import com.qmm.mapper.OrderMapper;
import com.qmm.pojo.Order;
import com.qmm.pojo.User;
import com.qmm.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
@Service
public class OrderServiceImpl implements OrderService {
@Autowired
OrderMapper orderMapper;
@Autowired
RestTemplate restTemplate;
@Autowired
UserClient userClient;
@Override
public Order queryOrderById(int orderId) {
// 1. 查询订单
Order order = orderMapper.findByID(orderId);
// // 2. 利用RestTemplate发起http请求
// String url = "http://userservice/user/" + order.getUserId();
// User user = restTemplate.getForObject(url, User.class);
// 2. 利用Feign发起http请求,查询用户
User user = userClient.findById(order.getUserId());
// 3. 封装user到order
order.setUser(user);
return order;
}
}
5.5 启动微服务,完成自测即可
总结
本文只是利用Nacos和Feign完成服务注册与远程调用的基本配置,就上述这样的一个配置过程我实践了很多次,恐怕现在还是不能一次调通,这期间遇到的问题包括但不限于:
- Spring Cloud Alibaba 与 Feign 版本不匹配
- pom.xml 依赖导入后,忘记刷新"Load Maven changes"
在写这篇文章的时候,我又发现了一个新问题且至今不知道原因,如下图,不添加注解@LoadBalanced
会报错
报错如下:
Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: org.springframework.web.client.ResourceAccessException: I/O error on GET request for "http://userservice/user/3": userservice] with root
就写到这吧,如有问题或者建议,欢迎提出!