美文网首页
03.`feign`→服务间的通信

03.`feign`→服务间的通信

作者: 风安峻_ | 来源:发表于2020-09-09 09:38 被阅读0次
    1. 依赖
    1. spring-cloud-starter-openfeign依赖

      <dependencies>
          <!-- feign -->
          <dependency>
              <groupId>org.springframework.cloud</groupId>
              <artifactId>spring-cloud-starter-openfeign</artifactId>
          </dependency>
      </dependencies>
      
    2. 说明

      1. 消费者添加spring-cloud-starter-openfeign的依赖即可,提供者不需要

      2. spring-cloud-starter-openfeign的父依赖

        <properties>
            <spring-cloud.version>Hoxton.SR7</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>
        
      3. 提供者注册到注册中心,消费者要从注册中心拉取提供者信息

        <properties>
             <spring-cloud-alibaba.version>2.2.1.RELEASE</spring-cloud-alibaba.version>
        </properties>
        
        <dependencies>
            <!-- nacos 注册中心 -->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            </dependency>
        </dependencies>
        
        <dependencyManagement>
            <!-- spring-cloud-alibaba 父依赖 -->
            <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>
        </dependencyManagement>    
        
    2. 配置
    1. feign-provider提供者

      1. application.yml主配置文件

        server:
          port: 8081
          servlet:
            # 提供者一般不设置前缀,这是为了演示
            context-path: /api/v1
        spring:
          application:
            # 注册到注册中心的服务名
            name: feign-provider
          cloud:
            nacos:
              discovery:
                # nacos注册中心的地址
                server-addr: 120.25.207.44:8848
                cluster-name: ${spring.application.name}
        
      2. 启动类

        import org.springframework.boot.SpringApplication;
        import org.springframework.boot.autoconfigure.SpringBootApplication;
        import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
        
        // 开启 nacos 注册中心扫描,发现该服务
        @EnableDiscoveryClient
        @SpringBootApplication
        public class FeignProviderApplication {
        
            public static void main(String[] args) {
                SpringApplication.run(FeignProviderApplication.class, args);
            }
        
        }
        
    2. feign-consumer消费者

      1. application.yml主配置文件

        server:
          port: 8082
        spring:
          application:
            # 注册到注册中心的服务名,不注册到注册中心可以不写
            name: feign-consumer
          cloud:
            nacos:
              discovery:
                # nacos 注册中心的地址
                server-addr: 120.25.207.44:8848
                # 不将自己注册到注册中心
                register-enabled: false
        feign:
          okhttp:
            # feign 启用 okhttp,性能最好
            enabled: true
        
      2. 启动类

        import org.springframework.boot.SpringApplication;
        import org.springframework.boot.autoconfigure.SpringBootApplication;
        import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
        import org.springframework.cloud.openfeign.EnableFeignClients;
        
        // 启动 feign 客户端
        @EnableFeignClients
        // 开启 nacos 注册中心扫描,发现该服务
        @EnableDiscoveryClient
        @SpringBootApplication
        public class FeignConsumerApplication {
        
            public static void main(String[] args) {
                SpringApplication.run(FeignConsumerApplication.class, args);
            }
        
        }
        
        • @EnableFeignClients启动feign客户端
        • @EnableDiscoveryClient开启注册中心扫描,发现该服务
    3. feign组件的使用
    1. feign-consumer消费者的远程调用类中用@FeignClient注解标记

      import org.springframework.cloud.openfeign.FeignClient;
      import org.springframework.stereotype.Service;
      
      @Service
      @FeignClient(value = "feign-provider", path = "/api/v1/provider")
      public interface ProviderService {
      
      }
      
      1. value = "feign-provider"的值feign-provider提供者注册到注册中心的服务名

        提供者的服务名
      2. path = "/api/v1/provider"是提供者的ProviderController的访问路径,/api/v1/是提供者在application.yml主配置文件配置的context-path

    2. 消费者远程调用类中,一个参数必须使用@RequestParam@PathVariable修饰,feign底层一个参数时会自动放进请求体中默认使用post请求(不用@RequestParam@PathVariable有可能取到的值为null),Get请求直接报错,提供者的controller可以不用@RequestParam修饰

      1. @RequestParam栗子,GetMapping或者PostMapping都可以

        1. 提供者controller

          import org.springframework.web.bind.annotation.*;
          
          @RestController
          @RequestMapping("/provider")
          public class ProviderController {
             @GetMapping("/testParam")
              public String testParam(String userId) {
                  return "ProviderController_testParam_" + userId;
              }
          
              @PostMapping("/testPostMappingParam")
              public String testPostMappingParam(String userId) {
                  return "ProviderController_testPostMappingParam_" + userId;
              }
          }
          
        2. 消费者

          1. 远程调用类

            import org.springframework.cloud.openfeign.FeignClient;
            import org.springframework.stereotype.Service;
            import org.springframework.web.bind.annotation.*;
            
            @Service
            @FeignClient(value = "feign-provider", path = "/api/v1/provider")
            public interface ProviderService {
                /**
                 * 对应 public String testParam(String userId){}
                 *
                 * @param userId 用户id
                 * @return 字符串
                 */
                @GetMapping("/testParam")
                String testParam(@RequestParam String userId);
            
                /**
                 * 对应 public String testPostMappingParam(String userId){}
                 *
                 * @param userId 用户id
                 * @return 字符串
                 */
                @PostMapping("/testPostMappingParam")
                String testPostMappingParam(@RequestParam String userId);
            }
            
          2. controller

            import com.sheng.cloud.feign.service.ProviderService;
            import org.springframework.web.bind.annotation.*;
            
            import javax.annotation.Resource;
            
            @RestController
            @RequestMapping("/consumer")
            public class ConsumerController {
                @Resource
                private ProviderService providerService;
             
                @GetMapping("/testParam")
                public String testParam(String userId) {
                    return providerService.testParam(userId);
                }
            
                @PostMapping("/testPostMappingParam")
                public String testPostMappingParam(String userId) {
                    return providerService.testPostMappingParam(userId);
                }
            }
            
      2. @PathVariable栗子,GetMapping或者PostMapping都可以

        1. 提供者controller

          import org.springframework.web.bind.annotation.*;
          
          @RestController
          @RequestMapping("/provider")
          public class ProviderController {
              @GetMapping("/testPathVariable/{userId}")
              public String testPathVariable(@PathVariable String userId) {
                  return "ProviderController_testPathVariable_" + userId;
              }
          }
          
        2. 消费者

          1. 远程调用类

            import org.springframework.cloud.openfeign.FeignClient;
            import org.springframework.stereotype.Service;
            import org.springframework.web.bind.annotation.*;
            
            @Service
            @FeignClient(value = "feign-provider", path = "/api/v1/provider")
            public interface ProviderService {
                /**
                 * 对应 public String testPathVariable(@PathVariable String userId){}
                 *
                 * @param userId 用户id
                 * @return 字符串
                 */
                @GetMapping("/testPathVariable/{userId}")
                String testPathVariable(@PathVariable String userId);
            }
            
          2. controller

            import com.sheng.cloud.feign.service.ProviderService;
            import org.springframework.web.bind.annotation.*;
            
            import javax.annotation.Resource;
            
            @RestController
            @RequestMapping("/consumer")
            public class ConsumerController {
                @Resource
                private ProviderService providerService;
             
                    @GetMapping("/testPathVariable/{userId}")
                    public String testPathVariable(@PathVariable String userId) {
                        return providerService.testPathVariable(userId);
                    }
            }
            
    3. 消费者远程调用类中,两个参数或以上必须使用@RequestParam@PathVariable修饰,不修饰不能启动,会直接报错。提供者的controller可以不用@RequestParam修饰

      1. @RequestParam栗子,GetMapping或者PostMapping都可以
        1. 提供者controller

          import org.springframework.web.bind.annotation.*;
          
          @RestController
          @RequestMapping("/provider")
          public class ProviderController {
              @PostMapping("/login")
              public String login(String username, String password) {
                  return "ProviderController_login_username: " + username + "_password: " + password;
              }
          }
          
        2. 消费者

          1. 远程调用类

            import org.springframework.cloud.openfeign.FeignClient;
            import org.springframework.stereotype.Service;
            import org.springframework.web.bind.annotation.*;
            
            @Service
            @FeignClient(value = "feign-provider", path = "/api/v1/provider")
            public interface ProviderService {
                /**
                 * 对应 public String login(String username, String password){}
                 *
                 * @param username 用户名
                 * @param password 密码
                 * @return 字符串
                 */
                @PostMapping("/login")
                String login(@RequestParam String username, @RequestParam String password);
            }
            
          2. controller

            import com.sheng.cloud.feign.service.ProviderService;
            import org.springframework.web.bind.annotation.*;
            
            import javax.annotation.Resource;
            
            @RestController
            @RequestMapping("/consumer")
            public class ConsumerController {
                @Resource
                private ProviderService providerService;
             
                @PostMapping("/login")
                public String login(String username, String password) {
                    return providerService.login(username, password);
                }   
            }
            
      2. @PathVariable栗子,GetMapping或者PostMapping都可以
        1. 提供者controller

          import org.springframework.web.bind.annotation.*;
          
          @RestController
          @RequestMapping("/provider")
          public class ProviderController {
              @GetMapping("/loginByPathVariable/{username}/{password}")
              public String loginByPathVariable(@PathVariable String username, @PathVariable String password) {
                  return "ProviderController_login_username: " + username + "password: " + password;
              }
          }
          
        2. 消费者

          1. 远程调用类

            import org.springframework.cloud.openfeign.FeignClient;
            import org.springframework.stereotype.Service;
            import org.springframework.web.bind.annotation.*;
            
            @Service
            @FeignClient(value = "feign-provider", path = "/api/v1/provider")
            public interface ProviderService {
                /**
                 * 对应 public String loginByPathVariable(@PathVariable String username, @PathVariable String password){}
                 *
                 * @param username 用户名
                 * @param password 密码
                 * @return 字符串
                 */
                @GetMapping("/loginByPathVariable/{username}/{password}")
                String loginByPathVariable(@PathVariable String username, @PathVariable String password);
            }
            
          2. controller

            import com.sheng.cloud.feign.service.ProviderService;
            import org.springframework.web.bind.annotation.*;
            
            import javax.annotation.Resource;
            
            @RestController
            @RequestMapping("/consumer")
            public class ConsumerController {
                @Resource
                private ProviderService providerService;
             
                @GetMapping("/loginByPathVariable/{username}/{password}")
                public String loginByPathVariable(@PathVariable String username, @PathVariable String password) {
                    return providerService.loginByPathVariable(username, password);
                }   
            }
            
    4. 如果消费者远程调用类的形参是JavaBean对象,那么提供者的controller对应的方法的形参必须用@RequestBody标记,否则取到的值为null,因为feign底层默认将对象序列化成json数据进行传递。

      1. 结果

        1. 不用@RequestBody修饰

          不用@RequestBody修饰
        2. @RequestBody修饰

          @RequestBody修饰
      2. 栗子

        1. 提供者controller

          import com.sheng.cloud.feign.dto.UserDto;
          import org.springframework.web.bind.annotation.*;
          
          @RestController
          @RequestMapping("/provider")
          public class ProviderController {
              @PostMapping("/getUser")
              public UserDto getUser(@RequestBody UserDto userDto) {
                  return userDto;
              }
          }
          
        2. 消费者

          1. 远程调用类

            import com.sheng.cloud.feign.dto.UserDto;
            import org.springframework.cloud.openfeign.FeignClient;
            import org.springframework.stereotype.Service;
            import org.springframework.web.bind.annotation.*;
            
            @Service
            @FeignClient(value = "feign-provider", path = "/api/v1/provider")
            public interface ProviderService {
                /**
                 * 对应 public UserDto getUser(@RequestBody UserDto userDto){}
                 *
                 * @param userDto 对象
                 * @return UserDto
                 */
                @PostMapping("/getUser")
                UserDto getUser(UserDto userDto);
            }
            
          2. controller

            import com.sheng.cloud.feign.dto.UserDto;
            import com.sheng.cloud.feign.service.ProviderService;
            import org.springframework.web.bind.annotation.*;
            
            import javax.annotation.Resource;
            
            @RestController
            @RequestMapping("/consumer")
            public class ConsumerController {
                @Resource
                private ProviderService providerService;
             
                @PostMapping("/getUser")
                public UserDto getUser(@RequestBody UserDto userDto) {
                    return providerService.getUser(userDto);
                }   
            }
            
    5. feign-demo 源码

    相关文章

      网友评论

          本文标题:03.`feign`→服务间的通信

          本文链接:https://www.haomeiwen.com/subject/xcdtektx.html