Spring Cloud整合Thrift RPC(二) - 应用
前言
上一篇简单的阐述了 spring-cloud-thrift-starter
这个插件的配置和使用,并引入了一个calculator
的项目。本文将基于一个银行存款、取款的业务场景,给出一套thrift
在生产环境的应用案例。
首先设计如下几张简单的数据库表:银行(bank
)、分支(branch
)、银行卡(deposit_card
)、客户(customer
)、存款历史纪录(deposit_history
)、取款历史纪录(withdraw_history
)。
正文
项目结构如下,依然是由三个模块组成:
image- 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
中间契约(deposit-iface)
将上述源文件拷贝到 deposit-iface
模块中。
通过Mybatis
逆向工程插件生成SQLMapper
的XML
和接口文件以及实体类。
友情提示:
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-server:
thrift
服务端的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-client:
thrift
客户端的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
服务代理接口,代理服务ID
为deposit-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
)内,为了提高服务的性能和吞吐量,而引入诸如Thrift
的RPC
框架,编程难度和复杂度是会大大提高的。好比一把双刃剑,技术选型时还需要多方面权衡利弊。
欢迎关注技术公众号: 零壹技术栈
零壹技术栈本帐号将持续分享后端技术干货,包括虚拟机基础,多线程编程,高性能框架,异步、缓存和消息中间件,分布式和微服务,架构学习和进阶等学习资料和文章。