The use of Feign under Spring cloud multi-module development, and the solution to the exception that @FeignClient injects beans and cannot find it

1. About Feign

In the development of microservice architecture, we often call other services in a project. In fact, this requirement can be achieved using Spring Cloud Ribbon. RestTemplate’s request interception is used to implement interface calls to dependent services. However, in actual projects, service dependencies There may be more than one call, and often an interface will be called in multiple places, so we usually encapsulate some client classes for each microservice to wrap the calls of these dependent services. At this time we will find that due to the encapsulation of RestTemplate, almost every call is simple templated content.

Spring Cloud Feign further encapsulates it on this basis to help us define and implement the definition of dependent service interfaces. Under the implementation of Spring Cloud Feign, we only need to create an interface and configure it using annotations (@FeignClient) to complete the interface binding to the service provider. This simplifies the development of self-encapsulated service call clients when using Spring Cloud Ribbon.

2. Build a Feign project in a multi-module way

1**, preparation,**

Start an Eureka service registration center, and the next two services will start and register on this.

2**, Writing First Service – Commodity Service**

(1). Create a parent module

File–>New–>Project–>Maven

There is no need to check anything, just fill in the GAV and then fill in the project name.

Because this is a parent module, you can directly delete the src file for the created Maven project.

(2). Create submodule common

Right-click `New`–>`Module` on the parent module to create a module, which is a submodule;

Also do not select the Create from archetype option because it is an ordinary module, Next;

GroupId The groupId of the default parent project

Version default parent project version

ArtifactId The name of this module product-common

Then fill in the project name and common

(3). Create the submodule client in the same way

Right-click `New`–>`Module` on the parent module to create a submodule;

Also do not select the Create from archetype option because it is an ordinary module, Next;

GroupId The groupId of the default parent project

Version default parent project version

ArtifactId The name of this module product-client

Then fill in the project name and you can client

(4). Create the sub-module server in the same way

Right-click `New`–>`Module` on the parent module to create a submodule;

Also do not select the Create from archetype option because it is an ordinary module, Next;

GroupId The groupId of the default parent project

Version default parent project version

ArtifactId The name of this module product-server

Then fill in the project name and server

(5). Write a service interface under the server module

For example, provide a **/product/listForOrder****, **this service will be called in the following order class

@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). Create an interface class under the client module

Add the annotation _@FeignClient(name = “product”)_ to this interface class, where product is the name of the configured service in the registration center

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). Submit this project to the Maven repository

You can directly use the install in Maven Projects on the right side of Idea, package and submit it to the Maven warehouse, or use the Maven command:

mvn -Dmaven.test.skip=true -U clean install

(8). Start the project and register the project to the registration center,


After successful startup, you will see the registration information of the service on the UI of the registration center.

3**, writing the second service-order service**

(1). Create an order Maven project just like creating a product project in Section 2.2.

(2). Introduce product client dependencies into the project

(3). Add annotations to the application startup class of the Server module of the order item

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients(basePackages = "com.yore.product.client")
public class OrderApplication {

? public static void main(String[] args) {
? SpringApplication.run(OrderApplication.class,args);
?}

}

(4). Call product services in the Server module

For example, when calling at the service layer, you only need to automatically annotate the ProductClient interface provided by the order class in this class, and you can use the interface services provided by the product class.

3. Dependencies introduced by the project

Spring Cloud is indeed more convenient to develop, and Spring Cloud version updates are also very fast, but the headache is the compatibility of each version, which is very inconvenient. Often due to version issues, it will be transferred into a pit and cannot extricate itself, so if sometimes after troubleshooting When you are sure that it is not a problem with the project code, you should downgrade to the stable version if there is really no other way.

1**, dependency of product reference**

parent pom file

<?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>

    <!-- Dependency version management -->
    <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 referenced in the project -->
            <dependency>
                <groupId>com.yore</groupId>
                <artifactId>product-common</artifactId>
                <version>${product-common.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

</project>

client module Pom file

<?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>
        <!-- The Feign annotation is used in the project and this package is introduced -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

        <!-- PostMapping is used in the project, introduce this package -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
        </dependency>

    </dependencies>

</project>

service module Pom file

<?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**, Dependencies referenced by the order class**

Parent Pom file

<?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 module Pom file

<?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>

4. Questions

1**, LoadBalancedRetryFactory class cannot be loaded exception**

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

This is a problem that occurs in some unofficial versions of Spring Cloud. Some people may not have this problem when using it. Sometimes this problem will occur when you are unlucky. If this problem occurs, don’t mess around with it. Just replace it with the stable official version. version, you can refer to the version introduced above and reimport it.

2**. Some Fegin services provided cannot be found**

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.

If this problem occurs, you must first determine whether the @EnableFeignClients annotation is added to the startup class, and the package basePackages = “com.yore.product.client” of the Feign client interface needs to be configured.

@EnableFeignClients(basePackages = "com.yore.product.client")

Then determine whether the Spring Cloud and Spring Boot versions referenced by the two services are consistent. Sometimes due to inconsistency, the annotations in the first service may refer to the package org.springframework.cloud.netflix.feign.FeignClient, and the other The service is referenced under the org.springframework.cloud.openfeign.FeignClient package, and this error will also be included at this time.