zoukankan      html  css  js  c++  java
  • 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<Store> getStores();
    
        @GetMapping(value = "/stores")
        Page<Store> 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 <code>@Qualifier</code> 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:方法级映射使用的路径前缀

    正文

    建立父工程

    next

    next

    Finish

    删除src目录

    建立Eureka工程

    给父工程添加module

    Next

    Next

    Next

    Finish

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

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

    建立公共模块工程

    Next

     Next

    Finish

    api的pom文件引入依赖

    <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-openfeign -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
        <version>2.2.3.RELEASE</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.12</version>
        <scope>provided</scope>
    </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; }

    目录结构如下

    建立服务提供者工程

    Next

    Next

    Next

    Finish

    将API的依赖添加进来

    <dependency>
        <groupId>com.example</groupId>
        <artifactId>cloud-api</artifactId>
        <version>1.0-SNAPSHOT</version>
    </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 注解

    建立服务接口

    package com.example.cloudprovider.service;
    
    import com.example.cloudapi.entity.User;
    
    import java.util.List;
    
    public interface UserService {
    
        List<User> 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<User> 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<User> getList(){
            return userService.getList();
        }
    }

    目录结构如下:

    启动测试

    Eureka里出现新的服务

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

    访问 http://localhost:8080/list

    建立服务消费者工程

    Next

    Next

    Next

    Finish

    将API的依赖添加进来

    <dependency>
        <groupId>com.example</groupId>
        <artifactId>cloud-api</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>

    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<User> 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<UserService> {
        public UserService create(Throwable throwable) {
            return new UserService() {
                public List<User> getList() {
                    return Collections.singletonList(new User(0, "服务提供者异常,使用消费者的降级信息"));
                }
            };
        }
    }

    api工程目录结构

    回到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<User> 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

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

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

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

    优化项目结构

    如果你细心你会发现,打开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.0</modelVersion>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.3.1.RELEASE</version>
        </parent>
        
        <groupId>com.example</groupId>
        <artifactId>cloud-parent</artifactId>
        <packaging>pom</packaging>
        <version>1.0-SNAPSHOT</version>
    
        <!--模块-->
        <modules>
            <module>cloud-api</module>
            <module>cloud-eureka</module>
            <module>cloud-provider</module>
            <module>cloud-consumer</module>
        </modules>
    
        <!--公共属性-->
        <properties>
            <java.version>1.8</java.version>
            <spring-cloud.version>Hoxton.SR6</spring-cloud.version>
        </properties>
    
        <!--Cloud依赖-->
        <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>
            </dependencies>
        </dependencyManagement>
    
        <!--构建参数-->
        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <configuration>
                        <source>${java.version}</source>
                        <target>${java.version}</target>
                        <encoding>UTF-8</encoding>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-clean-plugin</artifactId>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-jar-plugin</artifactId>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-dependency-plugin</artifactId>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-resources-plugin</artifactId>
                </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-parent</artifactId>
            <groupId>com.example</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
    
        <artifactId>cloud-api</artifactId>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-openfeign</artifactId>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
            </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.0</modelVersion>
        <parent>
            <groupId>com.example</groupId>
            <artifactId>cloud-parent</artifactId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        <artifactId>cloud-eureka</artifactId>
        <name>cloud-eureka</name>
        <description>Demo project for Spring Boot</description>
    
    
        <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>
                <exclusions>
                    <exclusion>
                        <groupId>org.junit.vintage</groupId>
                        <artifactId>junit-vintage-engine</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </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.0</modelVersion>
        <parent>
            <groupId>com.example</groupId>
            <artifactId>cloud-parent</artifactId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        <artifactId>cloud-provider</artifactId>
        <name>cloud-provider</name>
        <description>Demo project for Spring Boot</description>
    
    
        <dependencies>
            <dependency>
                <groupId>com.example</groupId>
                <artifactId>cloud-api</artifactId>
                <version>${project.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <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-netflix-hystrix</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
            </dependency>
            <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>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </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.0</modelVersion>
        <parent>
            <groupId>com.example</groupId>
            <artifactId>cloud-parent</artifactId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        <artifactId>cloud-consumer</artifactId>
        <name>cloud-consumer</name>
        <description>Demo project for Spring Boot</description>
    
        <dependencies>
            <dependency>
                <groupId>com.example</groupId>
                <artifactId>cloud-api</artifactId>
                <version>${project.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
            </dependency>
            <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>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    </project>

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

     Install后

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

  • 相关阅读:
    最快效率求出乱序数组中第k小的数
    调整数组顺序使奇数位于偶数前面
    分治算法的完美使用----归并排序
    快速排序分区以及优化方法
    分治法以及快速排序
    高效求a的n次幂的算法
    最长连续递增子序列(部分有序)
    在有空字符串的有序字符串数组中查找
    旋转数组的最小数字(改造二分法)
    递归----小白上楼梯
  • 原文地址:https://www.cnblogs.com/LUA123/p/13274318.html
Copyright © 2011-2022 走看看