原文:https://blog.csdn.net/github_39577257/article/details/81842234
一、關於Feign
在微服務架構開發是,我們常常會在一個項目中調用其他服務,其實使用Spring Cloud Rbbon就能實現這個需求,利用RestTemplate 的請求攔截來實現對依賴服務的接口調用, 但是實際項目中對服務依賴的調用可能不止於 一 處,往往 一 個接口會被多處調用,所以我們通常都會針對各個微服務自行封裝 一 些客戶端類來包裝這些依賴服務的調用。 這個時候我們會發現,由於 RestTemplate 的封裝,幾乎每 一 個調用都是簡單的模板化內容。
Spring Cloud Feign 在此基礎上做了進 一 步封裝,由它來幫助我們定義和實現依賴服務接口的定義。在 Spring Cloud Feign 的實現下, 我們只需創建 一 個接口並用注解(@FeignClient)的方式來配置它, 即可完成對服務提供方的接口綁定,簡化了在使用 Spring Cloud Ribbon 時自行封裝服務調用客戶端的開發量。
二、多模塊方式構建一個Feign項目
1、准備,
啟動一個Eureka服務注冊中心,后面的兩個服務都會啟動注冊到這個上面。
2、編寫第一服務--商品服務
(1). 創建一個父模塊
File-->New-->Project-->Maven
不需要任何勾選,直接填寫GAV,然后填寫項目名就可以了
因為這是一個父模塊,對於創建出來的Maven項目,可以直接刪除src文件
(2). 創建子模塊common
在父模塊上右鍵`New`-->`Module`,創建一個模塊,該模塊即為子模塊;
同樣不選擇Create from archetype選項,因為是普通模塊,Next;
GroupId 默認父項目的groupId
Version 默認父項目的version
ArtifactId 本模塊的名字product-common
然后填寫項目名即可common
(3). 同理創建子模塊client
在父模塊上右鍵`New`-->`Module`,創建一個子模塊;
同樣不選擇Create from archetype選項,因為是普通模塊,Next;
GroupId 默認父項目的groupId
Version 默認父項目的version
ArtifactId 本模塊的名字product-client
然后填寫項目名即可client
(4). 同理創建子模塊server
在父模塊上右鍵`New`-->`Module`,創建一個子模塊;
同樣不選擇Create from archetype選項,因為是普通模塊,Next;
GroupId 默認父項目的groupId
Version 默認父項目的version
ArtifactId 本模塊的名字product-server
然后填寫項目名即可server
(5). 在server模塊下編寫一個服務接口
例如提供一個/product/ listForOrder,這個服務會在下面的訂單類中調用
@RestController
@RequestMapping("/product")
public class ProductController {
@Autowired
private ProductService productService;
@PostMapping("/listForOrder")
public List<ProductInfoOutput> listForOrder(@RequestBody List<String> productIdList){
return productService.findList(productIdList);
}
}
(6). 在client模塊下創建一個接口類
在這個接口類上加注解@FeignClient(name = "product"),其中product是配置的服務在注冊中心上的名字
import com.yore.product.common.ProductInfoOutput;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import java.util.List;
@FeignClient(name = "product")
public interface ProductClient {
@PostMapping("/product/listForOrder")
List<ProductInfoOutput> listForOrder(@RequestBody List<String> productIdList);
}
(7). 接此項目提交到Maven倉庫
直接可以使用Idea右側的Maven Projects里的install,打包提交到Maven倉庫,或者使用Maven命令:
mvn -Dmaven.test.skip=true -U clean install
(8). 啟動項目,將項目注冊到注冊中心,
啟動成功后會在注冊中心的UI上看到服務的注冊信息
3、編寫第二服務—訂單服務
(1). 同第2.2創建商品項目一樣,創建一個訂單Maven項目
(2). 在項目中把商品類的client依賴引入項目
(3). 在訂單項目的Server模塊的應用啟動類上添加注解
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients(basePackages = "com.yore.product.client")
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class,args);
}
}
(4). 在Server模塊調用商品服務
這里比如在服務層調用,只需要在該類把訂單類提供的ProductClient接口自動注解進來,就可以使用商品類向外提供的接口服務
三、項目引入的依賴
Spring Cloud確實開發更加方便了,Spring Cloud版本更新也很快,但是頭疼的就是個個版本的兼容性就是很不方便的地方,經常因為版本問題會調入坑里不能自拔,所以如果有時排查后確定不是項目代碼問題時,實在沒有辦法時還是降版本吧。
1、商品類引用的依賴
父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.yore</groupId>
<artifactId>product</artifactId>
<version>0.0.1-SNAPSHOT</version>
<modules>
<module>common</module>
<module>client</module>
<module>server</module>
</modules>
<packaging>pom</packaging>
<name>product</name>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.4.RELEASE</version>
<relativePath/>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Finchley.M9</spring-cloud.version>
<product-common.version>0.0.1-SNAPSHOT</product-common.version>
</properties>
<!-- 依賴的版本管理 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- 項目中引用common -->
<dependency>
<groupId>com.yore</groupId>
<artifactId>product-common</artifactId>
<version>${product-common.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
client模塊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">
<parent>
<artifactId>product</artifactId>
<groupId>com.yore</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>product-client</artifactId>
<dependencies>
<!-- 項目中用到了Feign注解,引入此包 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- 項目中用到了PostMapping,引入此包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
</dependencies>
</project>
service模塊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">
<parent>
<artifactId>product</artifactId>
<groupId>com.yore</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>product-server</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2、訂單類引用的依賴
父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.yore</groupId>
<artifactId>order</artifactId>
<version>0.0.1-SNAPSHOT</version>
<modules>
<module>client</module>
<module>common</module>
<module>server</module>
</modules>
<packaging>pom</packaging>
<name>order</name>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.4.RELEASE</version>
<relativePath/>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Finchley.M9</spring-cloud.version>
<product-client.version>0.0.1-SNAPSHOT</product-client.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.yore</groupId>
<artifactId>product-client</artifactId>
<version>${product-client.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<repositories>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</pluginRepository>
<pluginRepository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</project>
server模塊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">
<parent>
<artifactId>order</artifactId>
<groupId>com.yore</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>order-server</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-context</artifactId>
</dependency>
<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>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.yore</groupId>
<artifactId>product-client</artifactId>
</dependency>
<dependency>
<groupId>com.yore</groupId>
<artifactId>order-common</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
四、問題
1、LoadBalancedRetryFactory類無法加載的異常
java.lang.IllegalStateException: Failed to introspect Class [org.springframework.cloud.openfeign.ribbon.FeignRibbonClientAutoConfiguration] from ClassLoader
Caused by: java.lang.NoClassDefFoundError: org/springframework/cloud/client/loadbalancer/LoadBalancedRetryFactory
這個是某些Spring Cloud非正式版本會出現的問題,有些人使用是可能不會出現這個問題,有時人品不好時就會包這個問題,出現這個問題就不要瞎折騰了,直接更換成正式版的吧,可以參考上面引入的版本,Reimport一下
2、提供的某些Fegin服務無法找到
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2018-08-19 21:28:20.526 ERROR 20068 --- [ main] o.s.b.d.LoggingFailureAnalysisReporter :
***************************
APPLICATION FAILED TO START
***************************
Description:
Field productClient in com.yore.order.service.impl.OrderServiceImpl required a bean of type 'com.yore.product.client.ProductClient' that could not be found.
Action:
Consider defining a bean of type 'com.yore.product.client.ProductClient' in your configuration.
出現這個問題,首先要確定在啟動類上是否添加了@EnableFeignClients注解,並且需要配置上Feign客戶端接口的包basePackages = "com.yore.product.client",
@EnableFeignClients(basePackages = "com.yore.product.client")
然后確定這兩個服務引用的Spring Cloud和Spring Boot版本是否一致,有時因為不一致,在 第一個服務中注解可能引用的是org.springframework.cloud.netflix.feign.FeignClient這個包下的,另一個服務中引用的是org.springframework.cloud.openfeign.FeignClient包下的,這時也會包這個錯誤,
————————————————
版權聲明:本文為CSDN博主「YoreYuan」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/github_39577257/article/details/81842234