SpringCloud第三弹(Feign客户端)

入职新公司,用的SpringCloud,重新开始学习一下

简介

之前接触Ribbon,可以知道调用微服务的方法是指定地址,然后通过RestTemplate来实现调用,用起来有点别扭,因为跟使用HttpClient来调用http接口的感觉是一样的,完全不是面向接口编程。

 Feign是一个声明性的Web服务客户端。它使编写Web服务客户端更加容易。要使用Feign,只需要创建一个接口 + 注释。比如:

@FeignClient(name = "${feign.name}", url = "${feign.url}")
public interface StoreClient {
    @GetMapping(value = "/stores")
    List getStores();

    @GetMapping(value = "/stores")
    Page getStores(Pageable pageable);

    @PostMapping(value = "/stores/{storeId}", consumes = "application/json")
    Store update(@PathVariable("storeId") Long storeId, Store store);
}

关于FeignClient注解

public @interface FeignClient {

    /**
     * 可选协议前缀的服务名称。是name的同义词。无论是否提供url,都必须为所有客户端指定名称。可以指定为属性键,例如:${propertyKey}。
     * @return the name of the service with optional protocol prefix
     */
    @AliasFor("name")
    String value() default "";

    /**
     * @deprecated 已废弃,请使用name
     * @return the service id with optional protocol prefix
     */
    @Deprecated
    String serviceId() default "";

    /**
     * 指定bean名称,而不是服务名称
     * @return bean name instead of name if present
     */
    String contextId() default "";

    /**
     * @return value的同义词
     */
    @AliasFor("value")
    String name() default "";

    /**
     * @return the @Qualifier value for the feign client.
     */
    String qualifier() default "";

    /**
     * 服务地址
     * @return 绝对URL或可解析主机名(协议可选)。
     */
    String url() default "";

    /**
     * @return 是否应该解码404,而不是抛出feignexception
     */
    boolean decode404() default false;

    /**
     * 自定义的feign client配置类,可以配置{@link feign.codec.Decoder}, {@link feign.codec.Encoder}, {@link feign.Contract}.等等
     * @see FeignClientsConfiguration for the defaults
     * @return list of configurations for feign client
     */
    Class[] configuration() default {};

    /**
     * 指定fallback类。fallback类必须实现由该注解注释的接口,并且必须是一个有效的spring bean。
     * @return fallback class for the specified Feign client interface
     */
    Class fallback() default void.class;

    /**
     * 指定FallbackFactory,FallbackFactory生成的实例必须实现由 @FeignClient 注释的接口,并且必须是一个有效的spring bean。
     * @see feign.hystrix.FallbackFactory for details.
     * @return fallback factory for the specified Feign client interface
     */
    Class fallbackFactory() default void.class;

    /**
     * @return 所有方法级映射使用的路径前缀
     */
    String path() default "";

    /**
     * @return whether to mark the feign proxy as a primary bean. Defaults to true.
     */
    boolean primary() default true;

}

主要这几个:

name和value:服务名称
contextId:bean名称
url:服务地址
configuration:配置类
fallback:容错处理类,需要实现注解了@FeignClient的接口
path:方法级映射使用的路径前缀

正文

建立父工程

SpringCloud第三弹(Feign客户端)_第1张图片

next

SpringCloud第三弹(Feign客户端)_第2张图片

next

SpringCloud第三弹(Feign客户端)_第3张图片

Finish

SpringCloud第三弹(Feign客户端)_第4张图片

删除src目录

建立Eureka工程

给父工程添加module

SpringCloud第三弹(Feign客户端)_第5张图片

Next

SpringCloud第三弹(Feign客户端)_第6张图片

Next

SpringCloud第三弹(Feign客户端)_第7张图片

Next

SpringCloud第三弹(Feign客户端)_第8张图片

Finish

SpringCloud第三弹(Feign客户端)_第9张图片

修改application.properties,加入

spring.application.name=eureka-registry-center

server.port=8888
# 不向注册中心注册自己
eureka.client.register-with-eureka=false
# 自己是注册中心
eureka.client.fetch-registry=false

eureka.client.serviceUrl.defaultZone=http://localhost:${server.port}/eureka/

修改启动类,加入 @EnableEurekaServer

SpringCloud第三弹(Feign客户端)_第10张图片

启动,并访问 http://localhost:8888/

SpringCloud第三弹(Feign客户端)_第11张图片

建立公共模块工程

SpringCloud第三弹(Feign客户端)_第12张图片

Next

SpringCloud第三弹(Feign客户端)_第13张图片

 Next

SpringCloud第三弹(Feign客户端)_第14张图片

Finish

api的pom文件引入依赖


<dependency>
    <groupId>org.springframework.cloudgroupId>
    <artifactId>spring-cloud-starter-openfeignartifactId>
    <version>2.2.3.RELEASEversion>
dependency>

<dependency>
    <groupId>org.projectlombokgroupId>
    <artifactId>lombokartifactId>
    <version>1.18.12version>
    <scope>providedscope>
dependency>

新建实体类

package com.example.cloudapi.entity;

import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@NoArgsConstructor @Getter @Setter
public class User { public User(Integer id, String name) { this.id = id; this.name = name; } private Integer id; private String name; }

目录结构如下

SpringCloud第三弹(Feign客户端)_第15张图片

建立服务提供者工程

SpringCloud第三弹(Feign客户端)_第16张图片

Next

SpringCloud第三弹(Feign客户端)_第17张图片

Next

SpringCloud第三弹(Feign客户端)_第18张图片

Next

SpringCloud第三弹(Feign客户端)_第19张图片

Finish

将API的依赖添加进来

<dependency>
    <groupId>com.examplegroupId>
    <artifactId>cloud-apiartifactId>
    <version>1.0-SNAPSHOTversion>
dependency>

修改application.properties

spring.application.name=service-provider
server.port=8080

eureka.client.service-url.defaultZone=http://localhost:8888/eureka
eureka.instance.instance-id=service-provider
eureka.instance.prefer-ip-address=true

修改启动类,增加  @EnableEurekaClient 注解

SpringCloud第三弹(Feign客户端)_第20张图片

建立服务接口

package com.example.cloudprovider.service;

import com.example.cloudapi.entity.User;

import java.util.List;

public interface UserService {

    List getList();
}

服务实现

package com.example.cloudprovider.service.impl;

import com.example.cloudapi.entity.User;
import com.example.cloudprovider.service.UserService;
import org.springframework.stereotype.Service;

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

@Service
public class UserServiceImpl implements UserService {
    @Override
    public List getList() {
        return Arrays.asList(new User(1, "小红"),new User(2, "小明"));
    }
}

Controller

package com.example.cloudprovider.controller;

import com.example.cloudapi.entity.User;
import com.example.cloudprovider.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
public class UserController {

    private UserService userService;

    @Autowired
    public UserController(UserService userService) {
        this.userService = userService;
    }

    @GetMapping("/list")
    public List getList(){
        return userService.getList();
    }
}

目录结构如下:

SpringCloud第三弹(Feign客户端)_第21张图片

启动测试

Eureka里出现新的服务

实际上,如果不配置  eureka.instance.instance-id ,有个默认值【IP:spring.application.name:端口

访问 http://localhost:8080/list

SpringCloud第三弹(Feign客户端)_第22张图片

建立服务消费者工程

SpringCloud第三弹(Feign客户端)_第23张图片

Next

SpringCloud第三弹(Feign客户端)_第24张图片

Next

SpringCloud第三弹(Feign客户端)_第25张图片

Next

SpringCloud第三弹(Feign客户端)_第26张图片

Finish

将API的依赖添加进来


    com.example
    cloud-api
    1.0-SNAPSHOT

api工程,新建Feign接口

package com.example.cloudapi.api;

import com.example.cloudapi.entity.User;
import com.example.cloudapi.fallback.UserServiceFallbackFactory;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;

import java.util.List;

@FeignClient(name = "SERVICE-PROVIDER" ,fallbackFactory = UserServiceFallbackFactory.class )
public interface UserService {

    @GetMapping("/list")
    List getList();
}

再新建一个fallback接口,作用在于:如果提供者服务不可用,客户端可以返回默认内容

package com.example.cloudapi.fallback;

import com.example.cloudapi.api.UserService;
import com.example.cloudapi.entity.User;
import feign.hystrix.FallbackFactory;
import org.springframework.stereotype.Component;

import java.util.Collections;
import java.util.List;

@Component
public class UserServiceFallbackFactory implements FallbackFactory {
    public UserService create(Throwable throwable) {
        return new UserService() {
            public List getList() {
                return Collections.singletonList(new User(0, "服务提供者异常,使用消费者的降级信息"));
            }
        };
    }
}

api工程目录结构

SpringCloud第三弹(Feign客户端)_第27张图片

 

回到Consumer工程

新建Controller

package com.example.cloudconsumer.controller;

import com.example.cloudapi.api.UserService;
import com.example.cloudapi.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
public class UserController {

    private UserService userService;

    @Autowired
    public UserController(UserService userService) {
        this.userService = userService;
    }

    @GetMapping("/list")
    List getList(){
        return userService.getList();
    }
}

修改 application.properties文件

spring.application.name=service-consumer
server.port=8081

eureka.client.service-url.defaultZone=http://localhost:8888/eureka
eureka.client.register-with-eureka=false

feign.hystrix.enabled=true

修改启动类,增加相关注解

SpringCloud第三弹(Feign客户端)_第28张图片

 

启动消费者,访问 http://localhost:8081/list

SpringCloud第三弹(Feign客户端)_第29张图片

 如果把服务提供者停掉,再次访问

SpringCloud第三弹(Feign客户端)_第30张图片

优化项目结构

如果你细心你会发现,打开IDEA的maven管理是存在多个root的,所以我们修改一下pom文件,让工程更合理一些。

也就是:1. 子工程依赖父工程。2. 公共部分放在parent的pom文件里。优化之后:

parent

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.0modelVersion>
    <parent>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-parentartifactId>
        <version>2.3.1.RELEASEversion>
    parent>
    
    <groupId>com.examplegroupId>
    <artifactId>cloud-parentartifactId>
    <packaging>pompackaging>
    <version>1.0-SNAPSHOTversion>

    
    <modules>
        <module>cloud-apimodule>
        <module>cloud-eurekamodule>
        <module>cloud-providermodule>
        <module>cloud-consumermodule>
    modules>

    
    <properties>
        <java.version>1.8java.version>
        <spring-cloud.version>Hoxton.SR6spring-cloud.version>
    properties>

    
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloudgroupId>
                <artifactId>spring-cloud-dependenciesartifactId>
                <version>${spring-cloud.version}version>
                <type>pomtype>
                <scope>importscope>
            dependency>
        dependencies>
    dependencyManagement>

    
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.pluginsgroupId>
                <artifactId>maven-compiler-pluginartifactId>
                <configuration>
                    <source>${java.version}source>
                    <target>${java.version}target>
                    <encoding>UTF-8encoding>
                configuration>
            plugin>
            <plugin>
                <groupId>org.apache.maven.pluginsgroupId>
                <artifactId>maven-clean-pluginartifactId>
            plugin>
            <plugin>
                <groupId>org.apache.maven.pluginsgroupId>
                <artifactId>maven-jar-pluginartifactId>
            plugin>
            <plugin>
                <groupId>org.apache.maven.pluginsgroupId>
                <artifactId>maven-dependency-pluginartifactId>
            plugin>
            <plugin>
                <groupId>org.apache.maven.pluginsgroupId>
                <artifactId>maven-resources-pluginartifactId>
            plugin>
        plugins>
    build>
project>

API

 

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>cloud-parentartifactId>
        <groupId>com.examplegroupId>
        <version>1.0-SNAPSHOTversion>
    parent>
    <modelVersion>4.0.0modelVersion>

    <artifactId>cloud-apiartifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-openfeignartifactId>
        dependency>
        <dependency>
            <groupId>org.projectlombokgroupId>
            <artifactId>lombokartifactId>
            <optional>trueoptional>
        dependency>
    dependencies>


project>

 

Eureka

 

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.0modelVersion>
    <parent>
        <groupId>com.examplegroupId>
        <artifactId>cloud-parentartifactId>
        <version>1.0-SNAPSHOTversion>
    parent>
    <artifactId>cloud-eurekaartifactId>
    <name>cloud-eurekaname>
    <description>Demo project for Spring Bootdescription>


    <dependencies>
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-netflix-eureka-serverartifactId>
        dependency>

        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-testartifactId>
            <scope>testscope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintagegroupId>
                    <artifactId>junit-vintage-engineartifactId>
                exclusion>
            exclusions>
        dependency>
    dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-maven-pluginartifactId>
            plugin>
        plugins>
    build>
project>

 

Provider

 

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.0modelVersion>
    <parent>
        <groupId>com.examplegroupId>
        <artifactId>cloud-parentartifactId>
        <version>1.0-SNAPSHOTversion>
    parent>
    <artifactId>cloud-providerartifactId>
    <name>cloud-providername>
    <description>Demo project for Spring Bootdescription>


    <dependencies>
        <dependency>
            <groupId>com.examplegroupId>
            <artifactId>cloud-apiartifactId>
            <version>${project.version}version>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
        dependency>
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-netflix-hystrixartifactId>
        dependency>
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-netflix-hystrix-dashboardartifactId>
        dependency>

        <dependency>
            <groupId>org.projectlombokgroupId>
            <artifactId>lombokartifactId>
            <optional>trueoptional>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-testartifactId>
            <scope>testscope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintagegroupId>
                    <artifactId>junit-vintage-engineartifactId>
                exclusion>
            exclusions>
        dependency>
    dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-maven-pluginartifactId>
            plugin>
        plugins>
    build>
project>

 

Consumer

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.0modelVersion>
    <parent>
        <groupId>com.examplegroupId>
        <artifactId>cloud-parentartifactId>
        <version>1.0-SNAPSHOTversion>
    parent>
    <artifactId>cloud-consumerartifactId>
    <name>cloud-consumername>
    <description>Demo project for Spring Bootdescription>

    <dependencies>
        <dependency>
            <groupId>com.examplegroupId>
            <artifactId>cloud-apiartifactId>
            <version>${project.version}version>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starterartifactId>
        dependency>
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
        dependency>

        <dependency>
            <groupId>org.projectlombokgroupId>
            <artifactId>lombokartifactId>
            <optional>trueoptional>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-testartifactId>
            <scope>testscope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintagegroupId>
                    <artifactId>junit-vintage-engineartifactId>
                exclusion>
            exclusions>
        dependency>
    dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-maven-pluginartifactId>
            plugin>
        plugins>
    build>
project>

 

这样的话,maven的结构是这样的

SpringCloud第三弹(Feign客户端)_第31张图片

 

 Install后

SpringCloud第三弹(Feign客户端)_第32张图片

 

 随后按照注册中心->服务提供者->服务消费者的顺序java -jar 启动即可。

 

你可能感兴趣的:(SpringCloud第三弹(Feign客户端))