问题
有时,我们需要通过变量的值来同步代码块。
为了解这个问题,我们将考虑一个简单的银行应用程序,它对客户的每次转账进行以下操作:
- 通过此外部Web服务转移评估现金返还金额(
CashBackService
) - 在数据库中执行汇款(
AccountService
) - 更新现金返还评估系统中的数据(
CashBackService
)
汇款操作如下:
public void withdrawMoney(UUID userId,int amountOfMoney){
synchronized(userId){
结果 result = externalCashBackService。evaluateCashBack(userId,amountOfMoney);
accountService。转移(用户id,amountOfMoney + 结果。getCashBackAmount());
externalCashBackService。cashBackComplete(用户id,结果。getCashBackAmount());
}
}
应用程序的基本组件如下图所示:
我试图尽可能清楚地做出一个例子。支付服务中的资金转移取决于其他两项服务:
- 第一个是
CashBackService
与REST协议下的另一个(外部)Web应用程序交互。而且,为了计算实际的现金返还,我们需要与此应用程序同步事务。这是因为下一笔现金返还金额可能取决于用户付款总额。 - 第二个是
AccountService
与内部数据库通信并存储与其用户帐户相关的数据。在此服务中,我们可以使用JPA事务在数据库中将某些操作作为原子操作。
在现实生活中,我强烈建议重构这样的系统,以避免这种情况,如果可能的话。但在我们的例子中,想象一下我们别无选择。
我们来看看这个应用程序的草案代码:
@服务
公共 类 PaymentService {
@Autowired
private ExternalCashBackService externalCashBackService ;
@Autowired
私人 AccountService 帐户服务 ;
public void withdrawMoney(UUID userId,int amountOfMoney){
synchronized(userId){
结果 result = externalCashBackService。evaluateCashBack(userId,amountOfMoney);
accountService。转移(用户id,amountOfMoney + 结果。getCashBackAmount());
externalCashBackService。cashBackComplete(用户id,结果。getCashBackAmount());
}
}
}
@服务
公共 类 ExternalCashBackService {
@Autowired
私人 RestTemplate restTemplate ;
public Result evaluateCashBack(UUID userId,int amountOfMoney){
return sendRestRequest(“evaluate”,userId,amountOfMoney);
}
public Result cashBackComplete(UUID userId,int cashBackAmount){
return sendRestRequest(“complete”,userId,cashBackAmount);
}
private Result sendRestRequest(String action,UUID userId,int value){
URI externalCashBackSystemUrl =
URI。create(“http://cash-back-system.org/api/” + action);
HttpHeaders headers = new HttpHeaders();
标题。集(“接受”,的MediaType。APPLICATION_JSON_VALUE);
RequestDto requestDto = new RequestDto(userId,value);
HttpEntity <?> request = new HttpEntity <>(requestDto,headers);
ResponseDto responseDto = restTemplate。exchange(externalCashBackSystemUrl,
HttpMethod。GET,
要求,
ResponseDto。课程)
。getBody();
返回 新的 结果(responseDto。的getStatus(),responseDto。的getValue());
}