One, foreword

After a project is divided into multiple services, the services will definitely call each other, for example, the purchase request needs to call commodity service to reduce inventory, call order service to create orders, call integral service to increase points, etc.

Open Feign calls services through interfaces that are very developer friendly.

Preparation: The database creates the following table

  • Id long
  • The name type String
  • The number type int
CREATE TABLE `product` (
	`id` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'primary key id',
	`name` VARCHAR(20) NOT NULL DEFAULT ' ' COMMENT 'Trade Name' COLLATE 'utf8mb4_general_ci',
	`number` INT(11) NOT NULL DEFAULT '0' COMMENT 'Quantity of goods'.PRIMARY KEY (`id`) USING BTREE
)
COLLATE='utf8mb4_general_ci'
ENGINE=InnoDB
;
Copy the code

And then add a random piece of commodity data

2. Directory structure

  • parentVersion Number Management
  • consumerService consumer
  • productGoods and services
  • product-apiCommodity service Interface

The next operation is that the Consumer service calls the Product service

Three,parentThe module

The parent module does version number management and only contains the POM.xml file

3.1 pom.xml


      
<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">
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.2</version>
        <relativePath/>
    </parent>

    <modelVersion>4.0.0</modelVersion>
    <groupId>com.llh</groupId>
    <artifactId>parent</artifactId>
    <version>1.0.0</version>
    <name>parent</name>
    <description>parent description</description>
    <packaging>pom</packaging>

    <properties>
        <spring-cloud.version>2020.0.2</spring-cloud.version>
        <spring-cloud-alibaba.version>2021.1</spring-cloud-alibaba.version>
        <mybatis.version>2.1.4</mybatis.version>
        <mybatis-plus.version>3.4.2</mybatis-plus.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.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring-cloud-alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>${mybatis.version}</version>
            </dependency>
            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus-boot-starter</artifactId>
                <version>${mybatis-plus.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>
</project>

Copy the code

Four,productCommodity Module (Service provider)

4.1 pom.xml


      
<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">
    <parent>
        <groupId>com.llh</groupId>
        <artifactId>parent</artifactId>
        <version>1.0.0</version>
        <relativePath/>
    </parent>

    <modelVersion>4.0.0</modelVersion>
    <artifactId>product</artifactId>
    <version>1.0.0</version>
    <name>product</name>
    <description>product description</description>

    <dependencies>
        <dependency>
            <groupId>com.llh</groupId>
            <artifactId>product-api</artifactId>
            <version>1.0.0</version>
        </dependency>

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

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
        </dependency>

    </dependencies>

</project>
Copy the code
  • The introduction of theproduct-apiThe module
  • The introduction of thespring-cloud-starter-openfeignRely on

4.2 application.properties

# application name spring. Application. Name = product for server port = 7777 # nacos service registry related spring. Cloud. Nacos. Discovery. The username = nacos spring.cloud.nacos.discovery.password=nacos spring.cloud.nacos.discovery.server-addr=http://localhost:8848 Spring. Cloud. Nacos. Discovery. The namespace = 83 e9d384 d49e - 4 # bf f40-84 - c25612883dcc database related spring.datasource.url=jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shang hai&useSSL=false spring.datasource.username=root spring.datasource.password=0320 Spring.datasource. Driver-class-name = com.mysql.cj.jdbc.driver # mybatis mybatis.mapper-locations=classpath:mapper/*Mapper.xmlCopy the code

4.3 ProductApplication

package com.llh.product;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/ * * *@authorTiger's tech blog */
@SpringBootApplication
@MapperScan(value = "com.llh.product.mapper")
public class ProductApplication {

    public static void main(String[] args) { SpringApplication.run(ProductApplication.class, args); }}Copy the code

4.4 ProductController

package com.llh.product.controller;

import com.llh.product.service.ProductService;
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;

import javax.annotation.Resource;

/ * * *@authorTiger's tech blog */
@RestController
@RequestMapping("/product")
public class ProductController {

    @Resource
    private ProductService productService;

    @GetMapping("/decrease/{productId}/{number}")
    public Boolean decrease(@PathVariable Long productId, @PathVariable Integer number) {
        returnproductService.decrease(productId, number); }}Copy the code

4.5 ProductServiceImpl

package com.llh.product.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.llh.product.api.entity.Product;
import com.llh.product.mapper.ProductMapper;
import com.llh.product.service.ProductService;
import org.springframework.stereotype.Service;

/ * * *@authorTiger's tech blog */
@Service
public class ProductServiceImpl extends ServiceImpl<ProductMapper.Product> implements ProductService {
    @Override
    public Boolean decrease(Long productId, Integer number) {
        Product product = getById(productId);
        // Determine if the quantity is sufficient
        if ((product.getNumber() - number) > 0) {
            // The quantity of goods decreases
            product.setNumber(product.getNumber() - number);
            return updateById(product);
        } else {
            return false; }}}Copy the code

Here is to reduce the inventory of goods, first judge the quantity of goods is enough, if enough to reduce.

Five,product-apiThe module

You can see that entity is placed in the Api module, because the Entity class is used by many services, so it is placed separately.

5.1 pom.xml


      
<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">
    <parent>
        <groupId>com.llh</groupId>
        <artifactId>parent</artifactId>
        <version>1.0.0</version>
        <relativePath/>
    </parent>

    <modelVersion>4.0.0</modelVersion>
    <artifactId>product-api</artifactId>
    <version>1.0.0</version>
    <name>product-api</name>
    <description>product api description</description>
    <packaging>jar</packaging>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

    </dependencies>
</project>

Copy the code

5.2 Productclass

public class Product {
    private Long id;
    private String name;
    private Integer number;
    
    // omit the setter getter
}

Copy the code

5.3 ProductApiclass

package com.llh.product.api.feign;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

/ * * *@authorTiger's tech blog */
@FeignClient(name = "product")
public interface ProductApi {
    /** * Reduce the number of goods **@paramProductId Commodity ID *@paramNumber number *@returnSuccessful */
    @GetMapping("/product/decrease/{productId}/{number}")
    Boolean decrease(@PathVariable Long productId, @PathVariable Integer number);
}

Copy the code

The key

  • through@FeignClient(name = "product")This annotation to find the service,productThat’s the service name.
  • The service caller callsdecreaseMethod, Open Feign will call the service nameproductthe @GetMapping("/product/decrease/{productId}/{number}")Interface.

Vi.consumerConsumer module (service caller)

6.1 pom.xml


      
<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">
    <parent>
        <groupId>com.llh</groupId>
        <artifactId>parent</artifactId>
        <version>1.0.0</version>
        <relativePath/>
    </parent>

    <modelVersion>4.0.0</modelVersion>
    <artifactId>consumer</artifactId>
    <version>1.0.0</version>
    <name>consumer</name>
    <description>consumer description</description>

    <dependencies>
        <dependency>
            <groupId>com.llh</groupId>
            <artifactId>product-api</artifactId>
            <version>1.0.0</version>
        </dependency>

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

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-loadbalancer</artifactId>
        </dependency>

    </dependencies>
</project>
Copy the code
  • spring-cloud-starter-openfeignspring-cloud-loadbalancerThese two dependencies.

6.2 application.properties

# application related to spring. Application. Name = consumer server port = 8888 # nacos service registry related spring. Cloud. Nacos. Discovery. The username = nacos spring.cloud.nacos.discovery.password=nacos spring.cloud.nacos.discovery.server-addr=http://localhost:8848 spring.cloud.nacos.discovery.namespace=83e9d384-d49e-4f40-84bf-c25612883dccCopy the code

6.3 ConsumerApplication

package com.llh.consumer;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;

/ * * *@authorTiger's tech blog */
@SpringBootApplication
@EnableFeignClients(basePackages = "com.llh.*")
public class ConsumerApplication {

    public static void main(String[] args) { SpringApplication.run(ConsumerApplication.class, args); }}Copy the code
  • Note: to addEnableFeignClientsAnnotation, scanning@FeignClientTo instantiate the Feign client

6.4 ConsumerController

package com.llh.consumer.controller;

import com.llh.consumer.service.ConsumerService;
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;

import javax.annotation.Resource;

/ * * *@authorTiger's tech blog */
@RestController
@RequestMapping("/consumer")
public class ConsumerController {
    @Resource
    private ConsumerService consumerService;

    @GetMapping("/buy/{productId}/{number}")
    public Boolean buy(@PathVariable Long productId, @PathVariable Integer number) {
        returnconsumerService.buy(productId, number); }}Copy the code

/consumer/buy/{productId}/{number}

6.4 ConsumerServiceImpl

package com.llh.consumer.service.impl;

import com.llh.consumer.service.ConsumerService;
import com.llh.product.api.feign.ProductApi;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;


/ * * *@authorTiger's tech blog */
@Service
public class ConsumerServiceImpl implements ConsumerService {
    @Resource
    private ProductApi productApi;

    @Override
    public Boolean buy(Long productId, Integer number) {
        productApi.decrease(productId, number);
        return true; }}Copy the code
  • Description:productApi.decreaseCall the remote service interface as if it were an internal method.

6.5 test

http://localhost:8888/consumer/buy/1/1

Request the interface, and you can see that the number of goods with id 1 is reduced by 1.

Call path: consumer–> product-API –> Product

Seven, conclusion

Multiple instances of a service are deployed in a production environment, and an Open Feign call randomly selects one instance. Of course, load balancing rules can be configured with polling, random, idle, etc.

Source code address: github.com/tigerleeli/…

There is a lot of pasting here (a bit verbose), and a lot of configuration files are put on the article, because I personally feel that for newcomers sometimes it’s just one or two packages or configuration files that don’t work. I don’t know if you like simple, just write key code. Prefer to be comprehensive and not leave out any details, like my article.