Spring Cloud整合Thrift RPC(二) - 應用案例

零壹技術棧發表於2018-06-20

前言

上一篇簡單的闡述了 spring-cloud-thrift-starter 這個外掛的配置和使用,並引入了一個calculator的專案。本文將基於一個銀行存款、取款的業務場景,給出一套thrift在生產環境的應用案例。

首先設計如下幾張簡單的資料庫表:銀行(bank)、分支(branch)、銀行卡(deposit_card)、客戶(customer)、存款歷史紀錄(deposit_history)、取款歷史紀錄(withdraw_history)。

Spring Cloud整合Thrift RPC(二) - 應用案例

正文

專案結構如下,依然是由三個模組組成:

Spring Cloud整合Thrift RPC(二) - 應用案例

  • deposit
    • deposit-client
    • deposit-iface
    • deposit-server

Thrift IDL編寫

關於 thrift更復雜的用法可以參考Apache Thrift基礎學習系列,根據資料庫表的設計編寫 deposit.thrift

deposit.thrift定義了以下四個部分:名稱空間 (namespace)、列舉型別 (enum)、結構型別 (struct)和服務型別 (service)。

(a). 名稱空間 (namespace)

// 指定編譯生成的原始碼的包路徑名稱
namespace java com.icekredit.rpc.thrift.examples.thrift
複製程式碼

(b). 列舉型別 (enum)

// 通過列舉定義銀行分支所屬區域
enum ThriftRegion {
   NORTH = 1,
   CENTRAL = 2,
   SOUTH = 3,
   EAST = 4,
   SOUTHWEST = 5,
   NORTHWEST = 6,
   NORTHEAST = 7
}

// 存款完成狀態
enum ThriftDepositStatus {
   FINISHED = 1,
   PROCCEDING = 2,
   FAILED = 3
}

// 取款完成狀態
enum ThriftWithdrawStatus {
   FINISHED = 1,
   PROCCEDING = 2,
   FAILED = 3
}
複製程式碼

(c). 結構型別 (struct)

// 銀行
struct ThriftBank {
   1: required i64 id,
   2: required string code,
   3: required string name,
   4: optional string description,
   5: optional map<ThriftRegion, list<ThriftBranch>> branches
}

// 銀行分支
struct ThriftBranch {
   1: required i64 id,
   2: required string code,
   3: required string name,
   4: required string address,
   5: optional i32 staffs,
   6: optional ThriftBank bank,
   7: optional ThriftRegion region
}

// 客戶
struct ThriftCustomer {
   1: required string IDNumber,
   2: required string name,
   3: required string birthday,
   4: required i32 sex = 0,
   5: required i32 age,
   6: optional list<string> address,
   7: optional set<ThriftDepositCard> depositCards
}

// 銀行卡
struct ThriftDepositCard {
   1: required string id,
   2: required bool isVip,
   3: required string openingTime,
   4: required double accountBalance,
   5: optional double accountFlow,
   6: optional ThriftBranch branch,
   7: optional ThriftCustomer customer,
   8: optional list<ThriftDeposit> depositHistory,
   9: optional list<ThriftWithdraw> WithdrawHistory
}

// 存款歷史紀錄
struct ThriftDeposit {
   1: required string serialNumber,
   2: required double transactionAmount,
   3: required string submittedTime,
   4: optional string finishedTime,
   5: optional ThriftDepositStatus status,
   6: optional ThriftDepositCard depositCard
}

// 取款歷史紀錄
struct ThriftWithdraw {
   1: required string serialNumber,
   2: required double transactionAmount,
   3: required string submittedTime,
   4: optional string finishedTime,
   5: optional ThriftWithdrawStatus status,
   6: optional ThriftDepositCard depositCard
}
複製程式碼

(d). 服務型別 (service)

// 銀行 - 業務服務定義
service ThriftBankService {
   void registerNewBank(ThriftBank bank);
   list<ThriftBank> queryAllBanks();
   ThriftBank getBankById(i64 bankId);
   map<ThriftRegion, list<ThriftBranch>> queryAllBranchesByRegion(i64 bankId);
}

// 銀行分支 - 業務服務定義
service ThriftBranchService {
   void addNewBranch(i64 bankId, ThriftBranch branch);
   list<ThriftBranch> queryAllBranches(i64 bankId);
   ThriftBranch getBranchById(i64 branchId);
}

// 客戶 - 業務服務定義
service ThriftCustomerService {
   ThriftCustomer getCustomerById(string customerId);
   list<ThriftCustomer> queryAllCustomers();
   void addNewUser(ThriftCustomer customer);
   void modifyUserById(string customerId, ThriftCustomer customer);
   i32 getTotalDepositCard(string customerId);

}

// 銀行卡 - 業務服務定義
service ThriftDepositCardService {
   set<ThriftDepositCard> queryAllDepositCards(string customerId);
   void addNewDepositCard(string customerId, ThriftDepositCard depositCard);
   ThriftDepositStatus depositMoney(string depositCardId, double money);
   ThriftWithdrawStatus withdrawMoney(string depositCardId, double money);
   list<ThriftDeposit> queryDepositHistorys(string depositCardId);
   list<ThriftWithdraw> queryWithdrawHistorys(string depositCardId);
}
複製程式碼

進入src/main/thrift目錄,編譯生成所需的列舉類結構類業務服務類的原始檔。

thrift -gen java ./deposit.thrift
複製程式碼

所有生成的原始檔都位於同一個**名稱空間(包)**下面:com.icekredit.rpc.thrift.examples.thrift

Spring Cloud整合Thrift RPC(二) - 應用案例

中間契約(deposit-iface)

上述原始檔拷貝到 deposit-iface 模組中。

Spring Cloud整合Thrift RPC(二) - 應用案例

通過Mybatis逆向工程外掛生成SQLMapperXML介面檔案以及實體類

友情提示Mybatis逆向工程生成的實體類 (entity),需要和Thrift編譯生成器生成的結構類 (struct) 區分開來。而Thrift生成器生成的所有原始檔,都一定程度封裝了底層的通訊方式相關協議,開發人員是不應該動手腳的。

為了在Thrift中通過Mybatis完成資料持久化,必須在實體類 (entity)包裝一層與結構類 (struct)相互轉換的方法。 在每個實體類中,根據業務新增以下兩個方法,以DepositCard為例:

  • toThrift():將實體類物件轉換為結構類物件
public ThriftDepositCard toThrift() {
    ThriftDepositCard thriftDepositCard = new ThriftDepositCard();
    thriftDepositCard.setId(this.getId());
    thriftDepositCard.setAccountBalance(this.getAccountBalance());
    thriftDepositCard.setAccountFlow(this.getAccountFlow());
    thriftDepositCard.setIsVip(this.getIsVip());
    thriftDepositCard.setOpeningTime(this.getOpeningTime());

    ThriftBranch thriftBranch = new ThriftBranch();
    thriftBranch.setId(this.getBranchId());
    thriftDepositCard.setBranch(thriftBranch);

    ThriftCustomer thriftCustomer = new ThriftCustomer();
    thriftCustomer.setIDNumber(this.getCustomerId());
    thriftDepositCard.setCustomer(thriftCustomer);
    return thriftDepositCard;
}
複製程式碼
  • fromThrift()靜態方法,將結構類物件轉換為實體類物件
public static DepositCard fromThrift(ThriftDepositCard thriftDepositCard) {
    DepositCard depositCard = new DepositCard();
    depositCard.setId(thriftDepositCard.getId());
    depositCard.setAccountBalance(thriftDepositCard.getAccountBalance());
    depositCard.setAccountFlow(thriftDepositCard.getAccountFlow());
    depositCard.setIsVip(thriftDepositCard.isIsVip());

    ThriftCustomer thriftCustomer = thriftDepositCard.getCustomer();
    if (thriftCustomer != null) {
        String customerIDNumber = thriftCustomer.getIDNumber();
        depositCard.setCustomerId(customerIDNumber);
    }

    ThriftBranch thriftBranch = thriftDepositCard.getBranch();
    if (thriftBranch != null) {
        Long branchId = thriftBranch.getId();
        depositCard.setBranchId(branchId);
    }

    depositCard.setOpeningTime(thriftDepositCard.getOpeningTime());
    return depositCard;
}
複製程式碼

服務端(deposit-server)

在服務端模組引入:

  • spring-cloud-starter-thrift-serverthrift服務端的 starter程式。
  • calculator-iface:中間契約模組,這裡作為服務端骨架(Skeleton)程式。

pom.xml

<parent>
    <groupId>com.icekredit.rpc.thrift.examples</groupId>
    <artifactId>deposit</artifactId>
    <version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>deposit-server</artifactId>
<packaging>jar</packaging>

<dependencies>
    <!-- Thrift相關依賴 -->
    <dependency>
        <groupId>com.icekredit.rpc.thrift</groupId>
        <artifactId>spring-cloud-starter-thrift-server</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
    <dependency>
        <groupId>com.icekredit.rpc.thrift.examples</groupId>
        <artifactId>deposit-iface</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
    <!-- SpringBoot依賴 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <!-- 資料庫相關依賴 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid-spring-boot-starter</artifactId>
        <version>1.1.5</version>
    </dependency>
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>1.3.0</version>
    </dependency>
    <!-- Swagger依賴 -->
    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger2</artifactId>
        <version>2.6.1</version>
    </dependency>
    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger-ui</artifactId>
        <version>2.6.1</version>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>
複製程式碼

application.yml中配置thrift服務端的執行引數資料來源連線池引數Mybatis相關屬性:

application.yml

server:
  port: 8080

endpoints:
  actuator:
    sensitive: false
    enabled: true
management:
  security:
    enabled: false

spring:
  datasource:
    druid:
      url: jdbc:mysql://localhost:3306/deposit?useUnicode=true&characterEncoding=utf-8
      driver-class-name: com.mysql.jdbc.Driver
      username: root
      password: root
  thrift:
    server:
      service-id: deposit-server-rpc
      service-model: hsHa
      port: 25000
      worker-queue-capacity: 1000
      hs-ha:
        min-worker-threads: 5
        max-worker-threads: 20
        keep-alived-time: 3

mybatis:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.icekredit.rpc.thrift.examples.http.entities

logging:
  level:
    root: INFO
    com:
      icekredit:
        rpc:
          thrift:
            examples:
              mapper: DEBUG
複製程式碼

服務端程式啟動入口類,設定 Swagger API所在的包路徑名稱。

Application.java

@SpringBootApplication
@EnableSwagger2
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Bean
    public Docket createRestfulApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.icekredit.rpc.thrift.examples.service.http.controller"))
                .paths(PathSelectors.any())
                .build();
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("Deposit Server")
                .description("Deposit Server")
                .version("1.0")
                .build();
    }
}
複製程式碼

編寫服務端的Thrift的實現,以ThriftDepositCardService為例,由實現類ThriftDepositCardServiceImpl實現ThriftDepositCardService.Iface介面的方法:

ThriftDepositCardServiceImpl.java

@ThriftService(name = "thriftDepositCardService")
public class ThriftDepositCardServiceImpl implements ThriftDepositCardService.Iface {
    private final BranchMapper branchMapper;
    private final DepositCardMapper depositCardMapper;
    private final CustomerMapper customerMapper;
    private final DepositHistoryMapper depositHistoryMapper;
    private final WithdrawHistoryMapper withdrawHistoryMapper;

    @Autowired
    public ThriftDepositCardServiceImpl(BranchMapper branchMapper, DepositCardMapper depositCardMapper, CustomerMapper customerMapper, DepositHistoryMapper depositHistoryMapper, WithdrawHistoryMapper withdrawHistoryMapper) {
        this.branchMapper = branchMapper;
        this.depositCardMapper = depositCardMapper;
        this.customerMapper = customerMapper;
        this.depositHistoryMapper = depositHistoryMapper;
        this.withdrawHistoryMapper = withdrawHistoryMapper;
    }

    @Override
    public Set<ThriftDepositCard> queryAllDepositCards(String customerId) throws TException {
        List<DepositCard> depositCardList = depositCardMapper.queryAllDepositCards(customerId);
        // 查詢客戶持有的銀行卡
        return depositCardList.stream().map(depositCard -> {
            ThriftDepositCard thriftDepositCard = depositCard.toThrift();
            Long branchId = depositCard.getBranchId();
            if (Objects.nonNull(branchId) && branchId > 0L) {
                Branch branch = branchMapper.findById(branchId);
                ThriftBranch thriftBranch = branch.toThrift();
                ThriftBank thriftBank = new ThriftBank();
                thriftBank.setId(branch.getBankId());
                thriftBranch.setBank(thriftBank);
                thriftDepositCard.setBranch(thriftBranch);
            }

            Customer customer = customerMapper.findById(customerId);
            ThriftCustomer thriftCustomer = customer.toThrift();
            thriftDepositCard.setCustomer(thriftCustomer);
            return thriftDepositCard;
        }).collect(Collectors.toSet());
    }

    @Override
    @Transactional
    public void addNewDepositCard(String customerId, ThriftDepositCard depositCard) throws TException {
        DepositCard newDepositCard = DepositCard.fromThrift(depositCard);
        // 新增銀行卡資訊
        depositCardMapper.save(newDepositCard);
    }

    @Override
    @Transactional
    public ThriftDepositStatus depositMoney(String depositCardId, double money) throws TException {
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        try {
            DepositHistory depositHistory = new DepositHistory();
            depositHistory.setSubmittedTime(sf.format(new Date()));
            depositCardMapper.incrementMoney(depositCardId, money);
            depositHistory.setFinishedTime(sf.format(new Date()));
            depositHistory.setSerialNumber(UUID.randomUUID().toString().replace("-", ""));
            depositHistory.setTransactionAmount(money);
            depositHistory.setDepositCardId(depositCardId);
            depositHistory.setStatus(1);
            // 新增存款歷史記錄
            depositHistoryMapper.save(depositHistory);
            return ThriftDepositStatus.FINISHED;
        } catch (Exception e) {
            e.printStackTrace();
            return ThriftDepositStatus.FAILED;
        }
    }

    @Override
    @Transactional
    public ThriftWithdrawStatus withdrawMoney(String depositCardId, double money) throws TException {
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        try {
            WithdrawHistory withdrawHistory = new WithdrawHistory();
            withdrawHistory.setSubmittedTime(sf.format(new Date()));
            depositCardMapper.decrementMoney(depositCardId, money);
            withdrawHistory.setFinishedTime(sf.format(new Date()));
            withdrawHistory.setSerialNumber(UUID.randomUUID().toString().replace("-", ""));
            withdrawHistory.setTransactionAmount(money);
            withdrawHistory.setDepositCardId(depositCardId);
            withdrawHistory.setStatus(1);
            // 新增取款歷史記錄
            withdrawHistoryMapper.save(withdrawHistory);
            return ThriftWithdrawStatus.FINISHED;
        } catch (Exception e) {
            e.printStackTrace();
            return ThriftWithdrawStatus.FAILED;
        }
    }

    @Override
    public List<ThriftDeposit> queryDepositHistorys(String depositCardId) throws TException {
        List<DepositHistory> depositHistory = depositHistoryMapper.queryDepositHistoryList(depositCardId);
        // 查詢存款歷史紀錄
        return depositHistory.stream().map(DepositHistory::toThrift).collect(Collectors.toList());
    }

    @Override
    public List<ThriftWithdraw> queryWithdrawHistorys(String depositCardId) throws TException {
        List<WithdrawHistory> withdrawHistory = withdrawHistoryMapper.queryWithdrawHistoryList(depositCardId);
        // 查詢取款歷史紀錄
        return withdrawHistory.stream().map(WithdrawHistory::toThrift).collect(Collectors.toList());
    }
}
複製程式碼

Mybatis持久層,還是以DepositCardMapper為例:

DepositCardMapper.java

@Repository
@Mapper
public interface DepositCardMapper {
    int save(DepositCard record);
    List<DepositCard> queryAllDepositCards(@Param("customerId") String customerId);
    void decrementMoney(@Param("depositCardId") String depositCardId, @Param("money") Double money);
    void incrementMoney(@Param("depositCardId") String depositCardId, @Param("money") Double money);
    Long countRowsByCustomerId(@Param("customerId") String customerId);
}
複製程式碼

DepositCardMapper.xml

<insert id="save" parameterType="com.icekredit.rpc.thrift.examples.http.entities.DepositCard">
    INSERT INTO deposit_card (id, is_vip, opening_time,
                              account_balance, account_flow, branch_id,
                              customer_id)
    VALUES (#{id,jdbcType=VARCHAR}, #{isVip,jdbcType=BIT}, #{openingTime,jdbcType=VARCHAR},
            #{accountBalance,jdbcType=DOUBLE}, #{accountFlow,jdbcType=DOUBLE}, #{branchId,jdbcType=BIGINT},
            #{customerId,jdbcType=VARCHAR})
</insert>

<select id="queryAllDepositCards" resultMap="BaseResultMap" parameterType="java.lang.String">
    SELECT
    <include refid="Base_Column_List"/>
    FROM deposit_card
    WHERE customer_id = #{customerId}
</select>

<select id="countRowsByCustomerId" resultType="java.lang.Long" parameterType="java.lang.String">
    SELECT COUNT(id)
    FROM deposit_card
    WHERE customer_id = #{customerId}
</select>

<update id="decrementMoney">
    UPDATE deposit_card
    <set>
        <if test="money != null">
            account_balance = account_balance - #{money},
        </if>
    </set>
    WHERE id = #{depositCardId}
</update>

<update id="incrementMoney">
    UPDATE deposit_card
    <set>
        <if test="money != null">
            account_balance = account_balance + #{money},
        </if>
    </set>
    WHERE id = #{depositCardId}
</update>
複製程式碼

客戶端(deposit-client)

同樣,在客戶端模組引入:

  • spring-cloud-starter-thrift-clientthrift客戶端的 starter程式。
  • deposit-iface:中間契約模組,這裡作為客戶端樁(Stub)程式。

pom.xml

<parent>
    <groupId>com.icekredit.rpc.thrift.examples</groupId>
    <artifactId>deposit</artifactId>
    <version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>deposit-client</artifactId>

<dependencies>
    <!-- Thrift相關依賴 -->
    <dependency>
        <groupId>com.icekredit.rpc.thrift</groupId>
        <artifactId>spring-cloud-starter-thrift-client</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
    <dependency>
        <groupId>com.icekredit.rpc.thrift.examples</groupId>
        <artifactId>deposit-iface</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
    <!-- SpringBoot依賴 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- Spring Cloud Consul服務註冊與發現 -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-consul-discovery</artifactId>
    </dependency>
    <!-- Spring Cloud宣告式Restful客戶端 -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-feign</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-ribbon</artifactId>
    </dependency>
    <!-- Swagger依賴 -->
    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger2</artifactId>
        <version>2.6.1</version>
    </dependency>
    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger-ui</artifactId>
        <version>2.6.1</version>
    </dependency>
</dependencies>

<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.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>
複製程式碼

application.yml中配置thrift的客戶端的的執行引數和 Consul 的服務註冊與發現的引數:

application.yml

server:
  port: 8080

endpoints:
  actuator:
    sensitive: false
    enabled: true
management:
  security:
    enabled: false

spring:
  cloud:
    consul:
      host: 192.168.91.128
      port: 8500
      discovery:
        register: false
        register-health-check: true
        health-check-interval: 30s
      retry:
        max-attempts: 3
        max-interval: 2000
  thrift:
    client:
      package-to-scan: com.icekredit.rpc.thrift.examples.thrift.client
      service-model: hsHa
      pool:
        retry-times: 3
        pool-max-total-per-key: 200
        pool-min-idle-per-key: 10
        pool-max-idle-per-key: 40
        pool-max-wait: 10000
        connect-timeout: 5000
複製程式碼

客戶端程式啟動入口類,設定 Swagger API所在的包路徑名稱,同時允許自身作為註冊程式註冊到註冊中心

@SpringBootApplication
@EnableFeignClients
@EnableDiscoveryClient
@EnableSwagger2
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Bean
    public Docket createRestfulApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.icekredit.rpc.thrift.examples"))
                .paths(PathSelectors.any())
                .build();
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("Deposit Client")
                .description("Deposit Client")
                .version("1.0")
                .build();
    }
}
複製程式碼

客戶端使用@ThriftClient註解標識服務端thrift服務代理介面代理服務IDdeposit-server-rpc代理的目標類ThriftDepositCardService

DepositCardThriftClient.java

@ThriftClient(serviceId = "deposit-server-rpc", refer = ThriftDepositCardService.class)
public interface DepositCardThriftClient extends ThriftClientAware<ThriftDepositCardService.Client> {
}
複製程式碼

BankThriftClient.java

@ThriftClient(serviceId = "deposit-server-rpc", refer = ThriftBankService.class)
public interface BankThriftClient extends ThriftClientAware<ThriftBankService.Client> {
}
複製程式碼

在客戶端控制器中通過ThriftReferer注入需要使用的服務代理介面,通過 thriftClient.client()即可獲取Thrift客戶端樁物件,然後實現遠端服務的呼叫。

DepositCardRpcController.java

@RestController
@RequestMapping("/rpc/deposit")
public class DepositCardRpcController {
    @ThriftReferer
    private DepositCardThriftClient thriftClient;

    @GetMapping("/queryAllDepositCards")
    public List<DepositCard> queryAllDepositCards(@RequestParam("customerId") String customerId)
            throws Exception {
        return thriftClient.client().queryAllDepositCards(customerId)
                .stream().map(DepositCard::fromThrift)
                .collect(Collectors.toList());
    }

    @PostMapping("/addNewDepositCard")
    public void addNewDepositCard(DepositCard depositCard) throws Exception {
        thriftClient.client().addNewDepositCard(depositCard.getCustomerId(), depositCard.toThrift());
    }

    @GetMapping("/depositMoney")
    public ThriftDepositStatus depositMoney(@RequestParam("depositCardId") String depositCardId,
                                            @RequestParam("money") double money) throws Exception {
        return thriftClient.client().depositMoney(depositCardId, money);
    }

    @GetMapping("/withdrawMoney")
    public ThriftWithdrawStatus withdrawMoney(@RequestParam("depositCardId") String depositCardId,
                                              @RequestParam("money") double money) throws Exception {
        return thriftClient.client().withdrawMoney(depositCardId, money);
    }

    @GetMapping("/queryDepositHistory")
    public List<DepositHistory> queryDepositHistory(@RequestParam("depositCardId") String depositCardId)
            throws Exception {
        return thriftClient.client().queryDepositHistorys(depositCardId)
                .stream().map(DepositHistory::fromThrift)
                .collect(Collectors.toList());
    }

    @GetMapping("/queryWithdrawHistory")
    public List<WithdrawHistory> queryWithdrawHistory(@RequestParam("depositCardId") String depositCardId)
            throws Exception {
        return thriftClient.client().queryWithdrawHistorys(depositCardId)
                .stream().map(WithdrawHistory::fromThrift)
                .collect(Collectors.toList());
    }
}
複製程式碼

BankRpcController.java

@RestController
@RequestMapping("/rpc/bank")
public class BankRpcController {
    @ThriftReferer
    private BankThriftClient thriftClient;

    @PostMapping("/addNewBank")
    public void addNewBank(Bank bank) throws Exception {
        thriftClient.client().registerNewBank(bank.toThrift());
    }

    @GetMapping("/getBankById")
    public Bank getBankById(@RequestParam("bankId") Long bankId) throws Exception {
        return Bank.fromThrift(thriftClient.client().getBankById(bankId));
    }

    @GetMapping("/queryAllBranchesByRegion")
    public Map<Region, List<Branch>> queryAllBranchesByRegion(@RequestParam("bankId") Long bankId) throws Exception {
        Map<ThriftRegion, List<ThriftBranch>> thriftRegionListMap = thriftClient.client()
                .queryAllBranchesByRegion(bankId);
        Map<Region, List<Branch>> regionListMap = new HashMap<>();

        for (Map.Entry<ThriftRegion, List<ThriftBranch>> entry : thriftRegionListMap.entrySet()) {
            ThriftRegion thriftRegion = entry.getKey();
            Region region = Region.findByValue(thriftRegion.getValue());

            List<ThriftBranch> thriftBranches = entry.getValue();
            List<Branch> branchList = thriftBranches.stream().map(Branch::fromThrift).collect(Collectors.toList());
            regionListMap.put(region, branchList);
        }
        return regionListMap;
    }
}
複製程式碼

因為服務代理客戶端介面使用@ThriftClient標識,通過(服務ID + 客戶端樁 + 版本號)唯一標識, 即使同時注入多個服務代理客戶端介面@ThriftReferer也可忽略註解屬性的配置。

總結

有一點是肯定的,那就是在已有技術框架(比如說:Spring + Mybatis/JPA)內,為了提高服務的效能吞吐量,而引入諸如ThriftRPC框架,程式設計難度複雜度是會大大提高的。好比一把雙刃劍,技術選型時還需要多方面權衡利弊。


歡迎關注技術公眾號: 零壹技術棧

零壹技術棧

本帳號將持續分享後端技術乾貨,包括虛擬機器基礎,多執行緒程式設計,高效能框架,非同步、快取和訊息中介軟體,分散式和微服務,架構學習和進階等學習資料和文章。

相關文章