(四)SpringCloud之Feign聲明式服務調用

入門案例

1、創建Maven聚合項目

在這裏插入圖片描述

  • Feign-Demo:父項目
  • eureka-server:Eureka註冊中心
  • eureka-server02:Eureka註冊中心
  • service-provider:服務提供者
  • service-consumer:服務消費者

父項目: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">
    <modelVersion>4.0.0</modelVersion>

    <groupId>cn.yanghuisen</groupId>
    <artifactId>Feign-Demo</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>eureka-server</module>
        <module>service-provider</module>
        <module>service-consumer</module>
    </modules>

    <!-- 繼承 spring-boot-starter-parent 依賴 -->
    <!-- 使用繼承方式,實現複用,符合繼承的都可以被使用 -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.0.RELEASE</version>
    </parent>

    <!--
        集中定義依賴組件版本號,但不引入,
        在子工程中用到聲明的依賴時,可以不加依賴的版本號,
        這樣可以統一管理工程中用到的依賴版本
     -->
    <properties>
        <!-- Spring Cloud Hoxton.SR5 依賴 -->
        <spring-cloud.version>Hoxton.SR5</spring-cloud.version>
    </properties>

    <!-- 項目依賴管理 父項目只是聲明依賴,子項目需要寫明需要的依賴(可以省略版本信息) -->
    <dependencyManagement>
        <dependencies>
            <!-- spring cloud 依賴 -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>


</project>

2、eureka註冊中心

2.1、eureka-server

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>Feign-Demo</artifactId>
        <groupId>cn.yanghuisen</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>eureka-server</artifactId>

    <name>eureka-server</name>
    <!-- FIXME change it to the project's website -->
    <url>http://www.example.com</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <!-- 項目依賴 -->
    <dependencies>
        <!-- netflix eureka server 依賴 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
        <!-- spring boot web 依賴 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- spring boot test 依賴 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>
</project>

application.yml

server:
  port: 8761 # 端口

spring:
  application:
    name: eureka-server # 應用名稱(集羣下相同)

# 配置 Eureka Server 註冊中心
eureka:
  instance:
    hostname: eureka01            # 主機名,不配置的時候將根據操作系統的主機名來獲取
    prefer-ip-address: true       # 是否使用 ip 地址註冊
    instance-id: ${spring.cloud.client.ip-address}:${server.port} # ip:port
  client:
    # 設置服務註冊中心地址,指向另一個註冊中心
    service-url:                  # 註冊中心對外暴露的註冊地址
      defaultZone: http://localhost:8762/eureka/

啓動類

package cn.yanghuisen;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@SpringBootApplication
// 開啓 EurekaServer 註解
@EnableEurekaServer
public class EurekaServerApplication {

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

}

2.2、eureka-server02

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>Feign-Demo</artifactId>
        <groupId>cn.yanghuisen</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>eureka-server02</artifactId>

    <name>eureka-server02</name>
    <!-- FIXME change it to the project's website -->
    <url>http://www.example.com</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <!-- 項目依賴 -->
    <dependencies>
        <!-- netflix eureka server 依賴 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
        <!-- spring boot web 依賴 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- spring boot test 依賴 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>
</project>

application.yml

spring:
  application:
    name: eureka-server # 應用名稱(集羣下相同)

# 端口
server:
  port: 8762

# 配置 Eureka Server 註冊中心
eureka:
  instance:
    hostname: eureka02            # 主機名,不配置的時候將根據操作系統的主機名來獲取
    prefer-ip-address: true       # 是否使用 ip 地址註冊
    instance-id: ${spring.cloud.client.ip-address}:${server.port} # ip:port
  client:
    # 設置服務註冊中心地址,指向另一個註冊中心
    service-url:                  # 註冊中心對外暴露的註冊地址
      defaultZone: http://localhost:8761/eureka/

啓動類

package cn.yanghuisen;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@SpringBootApplication
// 開啓 EurekaServer 註解
@EnableEurekaServer
public class EurekaServer02Application {

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

}

3、provider服務提供者

3.1、service-provider

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>Feign-Demo</artifactId>
    <groupId>cn.yanghuisen</groupId>
    <version>1.0-SNAPSHOT</version>
  </parent>
  <modelVersion>4.0.0</modelVersion>

  <artifactId>service-provider</artifactId>

  <name>service-provider</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
  </properties>

  <!-- 項目依賴 -->
  <dependencies>
    <!-- netflix eureka client 依賴 -->
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <!-- spring boot web 依賴 -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- lombok 依賴 -->
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <scope>provided</scope>
    </dependency>

    <!-- spring boot test 依賴 -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
      <exclusions>
        <exclusion>
          <groupId>org.junit.vintage</groupId>
          <artifactId>junit-vintage-engine</artifactId>
        </exclusion>
      </exclusions>
    </dependency>
  </dependencies>
</project>

實體類

package cn.yanghuisen.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Product implements Serializable {

    private Integer id;
    private String productName;
    private Integer productNum;
    private Double productPrice;

}

服務類接口

package cn.yanghuisen.service;


import cn.yanghuisen.pojo.Product;

import java.util.List;

/**
 * 商品服務
 */
public interface ProductService {

    /**
     * 查詢商品列表
     *
     * @return
     */
    List<Product> selectProductList();

}

服務類接口實現類

package cn.yanghuisen.service.impl;

import cn.yanghuisen.pojo.Product;
import cn.yanghuisen.service.ProductService;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.List;

/**
 * 商品服務
 */
@Service
public class ProductServiceImpl implements ProductService {

    /**
     * 查詢商品列表
     *
     * @return
     */
    @Override
    public List<Product> selectProductList() {
        return Arrays.asList(
                new Product(1, "華爲手機", 1, 5800D),
                new Product(2, "聯想筆記本", 1, 6888D),
                new Product(3, "小米平板", 5, 2020D)
        );
    }

}

控制層

package cn.yanghuisen.controller;

import cn.yanghuisen.pojo.Product;
import cn.yanghuisen.service.ProductService;
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;

import java.util.List;

@RestController
@RequestMapping("/product")
public class ProductController {

    @Autowired
    private ProductService productService;

    /**
     * 查詢商品列表
     *
     * @return
     */
    @GetMapping("/list")
    public List<Product> selectProductList() {
        return productService.selectProductList();
    }

}

啓動類

package cn.yanghuisen;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
// 開啓 EurekaClient 註解,目前版本如果配置了 Eureka 註冊中心,默認會開啓該註解
//@EnableEurekaClient
public class ServiceProviderApplication {

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

}

3.2、service-provider02

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>Feign-Demo</artifactId>
        <groupId>cn.yanghuisen</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>service-provider02</artifactId>

    <name>service-provider02</name>
    <!-- FIXME change it to the project's website -->
    <url>http://www.example.com</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <!-- 項目依賴 -->
    <dependencies>
        <!-- netflix eureka client 依賴 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!-- spring boot web 依賴 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- lombok 依賴 -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <scope>provided</scope>
        </dependency>

        <!-- spring boot test 依賴 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>
</project>

實體類

package cn.yanghuisen.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Product implements Serializable {

    private Integer id;
    private String productName;
    private Integer productNum;
    private Double productPrice;

}

服務類接口

package cn.yanghuisen.service;


import cn.yanghuisen.pojo.Product;

import java.util.List;

/**
 * 商品服務
 */
public interface ProductService {

    /**
     * 查詢商品列表
     *
     * @return
     */
    List<Product> selectProductList();

}

服務類接口實現類

package cn.yanghuisen.service.impl;

import cn.yanghuisen.pojo.Product;
import cn.yanghuisen.service.ProductService;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.List;

/**
 * 商品服務
 */
@Service
public class ProductServiceImpl implements ProductService {

    /**
     * 查詢商品列表
     *
     * @return
     */
    @Override
    public List<Product> selectProductList() {
        return Arrays.asList(
                new Product(1, "華爲手機", 1, 5800D),
                new Product(2, "聯想筆記本", 1, 6888D),
                new Product(3, "小米平板", 5, 2020D)
        );
    }

}

控制層

package cn.yanghuisen.controller;

import cn.yanghuisen.pojo.Product;
import cn.yanghuisen.service.ProductService;
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;

import java.util.List;

@RestController
@RequestMapping("/product")
public class ProductController {

    @Autowired
    private ProductService productService;

    /**
     * 查詢商品列表
     *
     * @return
     */
    @GetMapping("/list")
    public List<Product> selectProductList() {
        return productService.selectProductList();
    }

}

啓動類

package cn.yanghuisen;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
// 開啓 EurekaClient 註解,目前版本如果配置了 Eureka 註冊中心,默認會開啓該註解
//@EnableEurekaClient
public class ServiceProviderApplication {

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

}

4、consumer服務消費者

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>Feign-Demo</artifactId>
        <groupId>cn.yanghuisen</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>service-consumer</artifactId>

    <name>service-consumer</name>
    <!-- FIXME change it to the project's website -->
    <url>http://www.example.com</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <!-- 項目依賴 -->
    <dependencies>
        <!-- netflix eureka client 依賴 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            <!--去除jackson-dataformat-xml,否則會返回xml文件,而不是JSON-->
            <exclusions>
                <exclusion>
                    <groupId>com.fasterxml.jackson.dataformat</groupId>
                    <artifactId>jackson-dataformat-xml</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!-- spring cloud openfeign 依賴 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!-- spring boot web 依賴 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- lombok 依賴 -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <scope>provided</scope>
        </dependency>

        <!-- spring boot test 依賴 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>
</project>

eureka中默認集成com.fasterxml.jackson.dataformat,用於返回xml格式的數據,但是由於xml的等級比JSON高,所以在要返回JSON的時候,將會被替換爲XML,剔除com.fasterxml.jackson.dataformat後就可以正常返回JSON數據。

application.yml

server:
  port: 9090 # 端口

spring:
  application:
    name: service-consumer # 應用名稱

# 配置 Eureka Server 註冊中心
eureka:
  client:
    register-with-eureka: false         # 是否將自己註冊到註冊中心,默認爲 true
    registry-fetch-interval-seconds: 10 # 表示 Eureka Client 間隔多久去服務器拉取註冊信息,默認爲 30 秒
    service-url:                        # 設置服務註冊中心地址
      defaultZone: http://localhost:8761/eureka/,http://localhost:8762/eureka/

實體類

package cn.yanghuisen.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Product implements Serializable {

    private Integer id;
    private String productName;
    private Integer productNum;
    private Double productPrice;

}

package cn.yanghuisen.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;
import java.util.List;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Order implements Serializable {

    private Integer id;
    private String orderNo;
    private String orderAddress;
    private Double totalPrice;
    private List<Product> productList;

}

服務類接口

package cn.yanghuisen.service;

import cn.yanghuisen.pojo.Product;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;

import java.util.List;

// 聲明需要調用的服務
@FeignClient("service-provider")
public interface ProductService {

    /**
     * 查詢商品列表
     *
     * @return
     */
    // 配置需要調用的服務地址及參數
    @GetMapping("/product/list")
    List<Product> selectProductList();

}

package cn.yanghuisen.service;


import cn.yanghuisen.pojo.Order;

public interface OrderService {

    /**
     * 根據主鍵查詢訂單
     *
     * @param id
     * @return
     */
    Order selectOrderById(Integer id);

}

服務接口實現類

package cn.yanghuisen.service.impl;

import cn.yanghuisen.pojo.Order;
import cn.yanghuisen.service.OrderService;
import cn.yanghuisen.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class OrderServiceImpl implements OrderService {

    @Autowired
    private ProductService productService;

    /**
     * 根據主鍵查詢訂單
     *
     * @param id
     * @return
     */
    @Override
    public Order selectOrderById(Integer id) {
        return new Order(id, "order-001", "中國", 22788D,
                productService.selectProductList());
    }

}

控制層

package cn.yanghuisen.controller;

import cn.yanghuisen.pojo.Order;
import cn.yanghuisen.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.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/order")
public class OrderController {

    @Autowired
    private OrderService orderService;

    /**
     * 根據主鍵查詢訂單
     *
     * @param id
     * @return
     */
    @GetMapping("/{id}")
    public Order selectOrderById(@PathVariable("id") Integer id) {
        return orderService.selectOrderById(id);
    }

}

啓動類

package cn.yanghuisen;

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

@SpringBootApplication
// 開啓 EurekaClient 註解,目前版本如果配置了 Eureka 註冊中心,默認會開啓該註解
//@EnableEurekaClient
// 開啓 FeignClients 註解
@EnableFeignClients
public class ServiceConsumerApplication {

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

}

啓動項目,先啓動兩個註冊中心,再啓動兩個服務提供者,最後啓動服務消費者

訪問:http://localhost:9090/order/1

在這裏插入圖片描述

負載均衡

1、全局

@Bean
public RandomRule randomRule() {
    return new RandomRule();
}

2、局部

# 負載均衡策略
# service-provider 爲調用的服務的名稱
service-provider:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章