• Feign声明式服务调用


    Feign是一种声明式、模板化的HTTP客户端(仅在Application Client中使用)。声明式调用是指,就像调用本地方法一样调用远程方法,无需感知操作远程http请求。

    Spring Cloud的声明式调用, 可以做到使用 HTTP请求远程服务时能就像调用本地方法一样的体验,开发者完全感知不到这是远程方法,更感知不到这是个HTTP请求。Feign的应用,让Spring Cloud微服务调用像Dubbo一样,Application Client直接通过接口方法调用Application Service,而不需要通过常规的RestTemplate构造请求再解析返回数据。它解决了让开发者调用远程接口就跟调用本地方法一样,无需关注与远程的交互细节,更无需关注分布式环境开发。

    在使用Feign技术开发Spring Cloud微服务时,需要先抽取要注册发布的服务标准,将这套标准通过接口的形式定义出来。

    在Application Service端开发中,依赖抽取的服务标准接口工程,并对接口给予实现。

    在Application Client端开发中,依赖抽取的服务标准接口工程,并应用接口信息和Feign技术,实现远程服务的调用。

    在整体微服务开发中,Eureka Server作为注册中心必不可少,注册中心的作用不变,仍旧是注册和发现服务。

     一、Feign入门案例

    1.1 创建服务标准工程

    服务标准工程,是用于定义Application Service需要对外发布的服务标准接口的工程。这个工程中定义的接口需要使用SpringMVC中的注解来描述,所以工程依赖的资源必须有SpringMVC。在案例中,为了简化依赖复杂度,使用spring-boot中的spring-boot-starter-web资源依赖实现SpringMVC技术的导入。

    <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.0.1.RELEASE</version>
      </parent>
      

      <groupId>com.yucong</groupId>
      <artifactId>spring-cloud-04-feign-serviceapi</artifactId>
      <version>1.0</version>


      <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
      </properties>


      <dependencies>
        <!-- 主要使用其中的SpringMVC相关技术。将请求的URL和服务的方法耦合到一起。 -->
        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
      </dependencies>
      

      <build>
        <plugins>
          <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
          </plugin>
        </plugins>
      </build>


    </project>

    定义的服务接口和普通的服务接口没有太大的区别,但是为了让Feign技术可以识别到服务的访问URL,需要使用SpringMVC注解@RequestMapping来描述接口中定义的方法,代表方法对外提供服务时监听的URL路径是什么。

    /**
     * 微服务标准。
     * 是Application Service要提供的服务的标准。
     * 也是Application Client要调用远程服务的标准。
     * 就是一个普通的接口。
     */
    public interface FirstFeignService {
        
        /**
         * 测试GET请求的方法。
         * 请求不传递任何的参数。
         * 请求地址是 - /testFeign  -> http://ip:port/testFeign
         * @return
         */
        @RequestMapping(value="/testFeign", method=RequestMethod.GET)
        public List<String> testFeign();
    }

    1.2 创建Application Service 工程

    服务提供者在开发的时候,需要实现服务标准工程中定义的服务接口,并注册服务到Eureka Server注册中心上,所以需要依赖的资源必须有eureka和服务标准接口。

    <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.0.1.RELEASE</version>
      </parent>

      <groupId>com.yucong</groupId>
      <artifactId>spring-cloud-04-feign-appservice</artifactId>
      <version>1.0</version>

      <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
      </properties>

      <dependencyManagement>
        

        <dependencies>
          <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Finchley.SR1</version>
            <type>pom</type>
            <scope>import</scope>
          </dependency>
        </dependencies>


      </dependencyManagement>

      <dependencies>
      

        <!-- web启动器。 springmvc相关内容 -->
        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-test</artifactId>
          <scope>test</scope>
        </dependency>

        <!-- spring cloud 默认配置启动器 -->
        <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>

        <!-- 客户端依赖 -->
        <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

        <!-- 自定义的服务标准工程。 -->
        <dependency>
          <groupId>com.yucong</groupId>
          <artifactId>spring-cloud-04-feign-serviceapi</artifactId>
          <version>1.0</version>
        </dependency>

      </dependencies>

      <build>
        <plugins>
          <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
          </plugin>
        </plugins>
      </build>

    </project>

    在Spring Cloud微服务架构中,服务是由Controller对外提供的,是基于HTTP协议发布的REST服务。所以实现服务接口的是控制器。注意,服务不代表服务层代码。

    /**
     * 自定义的服务控制器
     * 对外提供服务的Application Service。
     * 不能随便的定义服务了。如果想让Application Client可以通过Feign技术访问当前类型提供的服务,
     * 则必须遵循服务标准。
     */
    @RestController
    public class TestFeignAppServiceController implements FirstFeignService {
    
        /**
         * 因为当前的方法都是实现接口FirstFeignService中的方法。
         * 而在接口中,已经将请求URL和方法耦合到一起了。
         * 所以在当前的控制器中,不能重复定义@RequestMapping来约束请求URL。
         */
        @Override
        public List<String> testFeign() {
            
            List<String> result = new ArrayList<>();
            
            result.add("test feign");
            result.add("this is first spring cloud with feign");
            
            return result;
        }
    
    }

    1.3 创建Application Client工程

    服务消费者在开发的时候,需要在Eureka Server中发现可用服务,并通过Feign来实现远程服务调用。在这个过程中,需要依赖于服务标准工程中定义的服务接口。

    <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.0.1.RELEASE</version>
      </parent>

      <groupId>com.yucong</groupId>
      <artifactId>spring-cloud-04-feign-appclient</artifactId>
      <version>1.0</version>
      

      <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
      </properties>

      <dependencyManagement>
        <dependencies>
          <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Finchley.SR1</version>
            <type>pom</type>
            <scope>import</scope>
          </dependency>
        </dependencies>
      </dependencyManagement>


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

        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-test</artifactId>
          <scope>test</scope>
        </dependency>
        

        <!-- spring cloud 默认配置启动器 -->
        <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>

        <!-- 客户端依赖 -->
        <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>


        <!-- feign启动器。封装了所有的feign相关资源的jar包。提供的是默认环境。
           feign技术在请求远程服务的时候,依托于http协议。
           默认底层使用JDK提供的HttpUrlConnection来实现http远程访问的。
           httpurlconnection技术不支持http连接池。所以效率上较低。
            -->
        <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

        <!-- 服务标准工程。 -->
        <dependency>
          <groupId>com.yucong</groupId>
          <artifactId>spring-cloud-04-feign-serviceapi</artifactId>
          <version>1.0</version>
        </dependency>
      </dependencies>
      

      <build>
        <plugins>
          <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
          </plugin>
        </plugins>
      </build>


    </project>

    在通过Feign来实现远程服务调用时,需要提供一个本地接口来继承服务标准工程提供的服务接口。这个本地接口不需要给予任何实现,在底层Spring容器会为这个接口提供一个基于JDK实现的代理对象,这个代理对象由Feign技术提供具体的HandlerInterceptor逻辑,实现远程的调用。实现过程类似通过代码调用LoadBalancerClient实现的Rest远程访问。

    而本地接口继承服务标准接口后,需要提供注解@FeignClient,注解的属性name代表当前接口要调用的远程服务的应用命名。

    /**
     * 本地接口,继承服务标准接口。
     * 在接口上增加注解@FeignClient,代表当前接口是一个Feign技术中的客户端。
     * 需要发起远程的http请求。
     * 注解有属性name - 代表当前的FeignClient在请求application service的时候,是调用哪一个服务?
     * 所谓的哪一个服务,就是application service全局配置文件中的spring.application.name属性值。
     */
    @FeignClient(name="test-feign-application-service")
    public interface FirstClientFeignService extends FirstFeignService {
    
    }

    控制器中可以像调用本地定义服务对象那样来调用远程服务。

    /**
     * Application Client中的控制器。是和用户直接交互的控制器。
     * 像平时开发代码一样。调用本地的一个service接口。通过service接口远程访问Application Service。
     */
    @RestController
    public class TestFeignAppClientController {
    
        /**
         * 本地定义的服务接口。用于实现远程调用application  service的接口。
         */
        @Autowired
        private FirstClientFeignService service;
        
        /**
         * 无参
         */
        @GetMapping("/testFeign")
        public List<String> testFeign(){
            System.out.println(this.service.getClass().getName());
            return this.service.testFeign();
        }
    
    }

    二、参数处理
    在Feign处理远程服务调用时,传递参数是通过HTTP协议传递的,参数存在的位置是请求头或请求体中。请求头传递的参数必须依赖@RequestParam注解来处理请求参数,请求体传递的参数必须依赖@RequestBody注解来处理请求参数。
    上述的要求是指Feign技术传递参数,也就是Application Client远程调用Application Service过程。

    2.1 处理请求头传参
    使用请求头传递参数时,定义的服务标准接口中,必须使用@RequestParam注解来描述方法参数,且注解属性value/name必须指定,代表从请求头中获取的请求参数命名是什么。
    在默认环境中,使用请求头传递参数时,Application Service中的控制器无法使用SpringMVC中的自动对象封装能力。只能处理简单数据类型。如:数学类型,字符串类型,数组类型等。无法处理自定义对象类型。

    2.2 处理请求体传参
    使用请求体传递参数时,定义的服务标准接口中,必须使用@RequestBody注解来描述方法参数,因为Feign技术发起的POST请求,请求参数是使用JSON字符串来传递的,且form表单类型为RAW。
    使用请求体传递参数时,Application Service中的控制器必须使用@RequestBody注解来描述方法参数,且RAW类型的form表单上传的是一个文本内容,只能转换为唯一的一个参数。
    如果使用POST方式提交请求,并传递多个普通类型的参数时,Feign不会通过请求体传递参数,是通过请求头传递的参数。也就是请求路径为 : http://applicationserver:port/url?paramName=paramValue

  • 相关阅读:
    【企业通讯录app番外篇】怎么样创建服务端?
    【android】activity的4种启动模式简介
    【android】开源一个企业通讯录app
    【android】来电悬浮窗
    【android Studio】零git知识、零脚本命令,即刻体验git版本管理魅力!
    【android】开发笔记---存储篇
    【android】activity、fragment传值例子
    写给过去了的那段时光
    react前端自动化webpack配置
    玩转webpack之webpack的entry output
  • 原文地址:https://www.cnblogs.com/yucongblog/p/11260061.html
Copyright © 2020-2023  润新知