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

前言

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

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

正文

項目結構以下,依然是由三個模塊組成:web

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

Thrift IDL編寫

關於 thrift更復雜的用法能夠參考Apache Thrift基礎學習系列,根據數據庫表的設計編寫 deposit.thriftspring

deposit.thrift定義瞭如下四個部分:命名空間 (namespace)、枚舉類型 (enum)、結構類型 (struct)和服務類型 (service)。sql

(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)api

// 銀行 - 業務服務定義
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

中間契約(deposit-iface)

上述源文件拷貝到 deposit-iface 模塊中。

經過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框架,編程難度複雜度是會大大提升的。比如一把雙刃劍,技術選型時還須要多方面權衡利弊。


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

零壹技術棧

本賬號將持續分享後端技術乾貨,包括虛擬機基礎,多線程編程,高性能框架,異步、緩存和消息中間件,分佈式和微服務,架構學習和進階等學習資料和文章。

相關文章
相關標籤/搜索