1. <acronym id="pirhh"><pre id="pirhh"><dd id="pirhh"></dd></pre></acronym>
        1. <tt id="pirhh"><pre id="pirhh"><dd id="pirhh"></dd></pre></tt>
          <rt id="pirhh"></rt> <code id="pirhh"><object id="pirhh"></object></code>
            <listing id="pirhh"><object id="pirhh"><tr id="pirhh"></tr></object></listing>
            <code id="pirhh"></code>

            Spring Cloud OpenFeign集成Protocol Buffer

            在之前的文章中,我們介紹過基于Spring Cloud微服務架構,其中,微服務實例之間的交互方式一般為RESTful HTTP請求或RPC調用。Spring Cloud已經為開發者提供了專門用于RESTful HTTP請求處理的OpenFeign組件,但是并沒有相關的RPC調用組件。今天,我們就要定制OpenFeign的編解碼器,使用Google的Protocol Buffer編碼,讓它擁有RPC調用的數據傳輸和轉換效率高的優點。

            OpenFeign是一個聲明式RESTful HTTP請求客戶端,它使得編寫Web服務客戶端更加方便和快捷。它有較強的定制性,可以根據自己的需求來對它的各個方面進行定制,比如說編解碼器,服務路由解析和負載均衡。

            而Protocol Buffer 是Google的一種輕便高效的結構化數據存儲格式,可以用于結構化數據串行化,或者說序列化。它很適合做數據存儲或 RPC 數據交換格式。可用于通訊協議、數據存儲等領域的語言無關、平臺無關、可擴展的序列化結構數據格式。目前提供了 C++、Java、Python 三種語言的 API。

            OpenFeign默認使用 HttpUrlConnection 進行網絡請求的發送; 相關實現代碼在 DefaultFeignLoadBalancedConfigurationClient.Default 。而其使用的編解碼器默認為jackson2,默認配置為 HttpMessageConvertersAutoConfiguration

            Protocol Buffer的編解碼效率要遠高于jackson2,在微服務實例頻頻通信的場景下,使用Protocol Buffer編解碼時會少占用系統資源,并且效率較高。具體詳見這個對比對比各種序列化和反序列化框架的性能的文檔, https://github.com/eishay/jvm-serializers/wiki。

            客戶端集成Protocol Buffer

            開發人員可以使用自定義配置類對OpenFeign進行定制,提供OpenFeign所需要的編解碼組件實例,從而替代默認的組件實例,達到定制化的目的。自定義的配置類如下所示。

            @Configuration
            public class ProtoFeignConfiguration{
                @Autowired
                private ObjectFactory<HttpMessageConverters> messageConverterObjectFactory;
                @Bean
                public ProtobufHttpMessageConverter protobufHttpMessageConverter(){
                    return new ProtobufHttpMessageConverter();
                }
            
                @Bean
                public Encoder springEncoder(){
                    return new SpringEncoder(this.messageConverterObjectFactory);
                }
            
                @Bean
                public Decoder springDecoder(){
                    return new ResponseEntityDecoder(new SpringDecoder(this.messageConverterObjectFactory));
                }
            }
            

            其中 ProtobufHttpMessageConverterHttpMessageConverters 的Protobuf的實現類,負責使用Protocol Buffer進行網絡請求和響應的編解碼。而 SpringEncoderResponseEntityDecoder 是OpenFeign中的編解碼器實現類。

            下面,我們來看一下OpenFeign中發送網絡請求的接口定義。 @FeignClient 中配置了 ProtoFeignConfiguration 為自定義配置類。

            @FeignClient(name = "user", configuration = ProtoFeignConfiguration.class)
            public interface UserClient {
                @RequestMapping(value = "/info", method = RequestMethod.GET,
                        consumes = "application/x-protobuf", produces = "application/x-protobuf")
                UserDTO getUserInfo(@RequestParam("id") Long id);
            }
            

            其中, UserDTO 是使用Protocol Buffer的maven插件自動生成的。需要注意的是,必須將 @RequestMappingconsumesproduces 屬性設置為 application/x-protobuf ,表示網絡請求和響應的編碼格式必須是Protobuf,否則可能會接收到406的錯誤響應碼。

            下面是proto文件中的數據格式定義,其中java_package是表明生成文件的目標文件夾。該文件中定義了UserDTO數據格式,它包括ID,名稱和主頁URL三個屬性。

            syntax = "proto3";
            
            option java_multiple_files = true;
            option java_package = "com.remcarpediem.feignprotobuf.proto.dto";
            
            package com.remcarpediem.feignprotobuf.proto.dto;
            
            message UserDTO {
                int32 id = 1;
                string name = 2;
                string url = 3;
            }
            

            在pom文件中配置build屬性,使用Protocol Buffer的maven插件可以自動根據proto文件生成Java代碼。每個配置項都在代碼中有對應的解釋。

            <build>
                    <plugins>
                        <plugin>
                            <groupId>org.xolstice.maven.plugins</groupId>
                            <artifactId>protobuf-maven-plugin</artifactId>
                            <version>0.5.0</version>
                            <extensions>true</extensions>
                            <configuration>
                                <!--默認值-->
                                <protoSourceRoot>${project.basedir}/src/main/proto</protoSourceRoot>
                                <!--默認值-->
                                <!--<outputDirectory>${project.build.directory}/generated-sources/protobuf/java</outputDirectory>-->
                                <outputDirectory>${project.build.sourceDirectory}</outputDirectory>
                                <!--設置是否在生成java文件之前清空outputDirectory的文件,默認值為true,設置為false時也會覆蓋同名文件-->
                                <clearOutputDirectory>false</clearOutputDirectory>
                                <!--默認值-->
                                <temporaryProtoFileDirectory>${project.build.directory}/protoc-dependencies</temporaryProtoFileDirectory>
                                <!--更多配置信息可以查看https://www.xolstice.org/protobuf-maven-plugin/compile-mojo.html-->
                            </configuration>
                            <executions>
                                <execution>
                                    <goals>
                                        <goal>compile</goal>
                                        <goal>test-compile</goal>
                                    </goals>
                                    <!--也可以設置成局部變量,執行compile或test-compile時才執行-->
                                    <!--<configuration>-->
                                    <!--<protoSourceRoot>${project.basedir}/src/main/proto</protoSourceRoot>-->
                                    <!--<outputDirectory>${project.build.directory}/generated-sources/protobuf/java</outputDirectory>-->
                                    <!--<temporaryProtoFileDirectory>${project.build.directory}/protoc-dependencies</temporaryProtoFileDirectory>-->
                                    <!--</configuration>-->
                                </execution>
                            </executions>
                        </plugin>
                    </plugins>
                </build>
            

            然后運行Protocol Buffer的maven插件可以自動生成相關的數據類。

            服務端

            然后是服務端對于Protocol Buffer的集成。我們也需要使用自定義配置類將 ProtobufHttpMessageConverter 設置為系統默認的編解碼器,如下述代碼所示。

            @Configuration
            public class Conf{
                @Bean
                ProtobufHttpMessageConverterprotobufHttpMessageConverter(){
                    return new ProtobufHttpMessageConverter();
                }
            }
            

            然后定義Controller的關于user的info接口。返回UserDTO實例作為網絡請求的返回值。 ProtobufHttpMessageConverter 會自動將其轉換為Protocol Buffer的數據格式進行傳輸。

            @RestController
            public class UserController{
                private String host = "http://blog.com/user/";
                @GetMapping("/info")
                public UserDTO getUserInfo(@RequestParam("id")Long id){
                    return UserDTO.newBuilder().
                            setId(id).setName("Tom").
                            setUrl(host + "Tom").build();
                }
            }
            

            本文的源碼地址: GitHub: https://github.com/ztelur/feign-protobuf

            總結

            欲了解更詳細的實現原理和細節,大家可以關注筆者出版的《Spring Cloud 微服務架構進階》,本書中對Spring Cloud Finchley.RELEASE版本的各個主要組件進行原理講解和實戰應用,里邊也有關于OpenFeign的原理和實現的詳細解析。更多的介紹見 Spring Cloud 微服務架構進階

            《Spring Cloud 微服務架構進階》預售地址: https://item.jd.com/12453340.html

            我來評幾句
            登錄后評論

            已發表評論數()

            相關站點

            +訂閱
            熱門文章
            天辰线上娱乐

            1. <acronym id="pirhh"><pre id="pirhh"><dd id="pirhh"></dd></pre></acronym>
                  1. <tt id="pirhh"><pre id="pirhh"><dd id="pirhh"></dd></pre></tt>
                    <rt id="pirhh"></rt> <code id="pirhh"><object id="pirhh"></object></code>
                      <listing id="pirhh"><object id="pirhh"><tr id="pirhh"></tr></object></listing>
                      <code id="pirhh"></code>

                      1. <acronym id="pirhh"><pre id="pirhh"><dd id="pirhh"></dd></pre></acronym>
                            1. <tt id="pirhh"><pre id="pirhh"><dd id="pirhh"></dd></pre></tt>
                              <rt id="pirhh"></rt> <code id="pirhh"><object id="pirhh"></object></code>
                                <listing id="pirhh"><object id="pirhh"><tr id="pirhh"></tr></object></listing>
                                <code id="pirhh"></code>