Biz-SIP业务中台之DDD架构实战:各层间的调用和依赖关系

Biz-SIP金融级业务中台(http://bizsip.bizmda.com)是一套基于领域驱动设计(DDD)架构,能快速构建金融级云原生架构的服务整合中间件,整合了在金融场景里锤炼出来的最佳实践。

软件设计的最大目标,就是降低复杂性。万物不为我所有,但万物皆为我用。
如何将复杂的软件系统分解成模块(如类和方法),这些模块可以相对独立的实现?
how to decompose complex software systems into modules (such as classes and methods) that can be implemented relatively independently.

领域驱动设计(DDD)所带来的改变,面向领域设计,面向对象编程,领域模型的抽象就是对现实世界的描述。

一、概述

xBank是一家商业银行,面向个人客户和公司客户,其中个人客户业务包括存款、贷款、缴费等业务;银行业务渠道除了传统柜面以外,还有网上银行、手机银行、ATM、POS等,最近准备上一个针对银行合作伙伴的基于OPENAPI网关的开放平台渠道。
本示例项目是以个人客户中的存款查询和缴费业务为例子,后台系统对接个人客户存款系统和个人客户信息系统,第三方对接缴费平台,来演示如何打造基于Biz-SIP中间件的银行业务中台。

xbank项目版本库:[https://gitee.com/szhengye/xbank.git]

xBank系统各层间的调用和依赖关系如下图所示:
在这里插入图片描述

1、Source层的XmlController

XmlController是一个RestController应用,主要完成以下处理:

  • 接收调用者发来的HTTP POST请求;
  • 通过消息转换器,把XML报文解包成平台标准格式报文;
  • 调用App层封装好的App服务;
  • 把App服务返回的平台标准格式报文,打包成XML报文并返回请求方。

代码如下:

@RestController
@RequestMapping("/personal")
public class XmlController {
    // 定义一个接口为PersonalAppInterface的,app层服务名为app/personal的服务调用句柄
    private PersonalAppInterface personalAppInterface = SourceClientFactory
            .getAppServiceClient(PersonalAppInterface.class,"app/personal");
    // 定义一个接口为平台标准JSON接口(类型固定为BizMessageInterface),app层服务名为sink/payment1的服务调用句柄
    private BizMessageInterface payment1SinkInterface = SourceClientFactory
            .getAppServiceClient(BizMessageInterface.class,"sink/payment1");
    // 获取source层消息格式转换器
    private Converter converter = Converter.getSourceConverter("xml-source");

    @PostMapping(value = "/getCustomerAndAccountList", consumes = "application/xml", produces = "application/xml")
    public String getCustomerAndAccountList(@RequestBody String inMessage) throws BizException {
        // 消息解包操作
        JSONObject jsonObject = this.converter.unpack(inMessage.getBytes());
        String customerId = (String)jsonObject.get("customerId");
        // 调用app层服务
        CustomerAndAccountList customerAndAccountList = this.personalAppInterface.getCustomerAndAccountList(customerId);
        jsonObject = JSONUtil.parseObj(customerAndAccountList);
        // 消息打包并返回
        return new String(this.converter.pack(jsonObject));
    }
	......
}

进阶要点

  • Source模块可以采用可复用的代码框架,把通用的Source通讯适配应用和个性化的Source服务分开,通用的Source通讯适配应用可以参见Biz-SIP源码中source模块中的子模块,目前有rest-source和netty-source,前一个是简单的HTTP RESTful POST接入的模块,后一个是用Netty封装的支持TCP同步短连接的模块。个性化的Source服务是继承并实现SourceServiceInterface接口,在其中的doService()方法实现通讯适配以外的工作,包括格式转换、调用App层服务等。

2、XmlController调用App服务

XmlController是通过申请App服务的调用接口,在申请调用接口时,会采用App层封装好的App服务Interface接口类:

public class XmlController {
    // 定义一个接口为PersonalAppInterface的,app层服务名为app/personal的服务调用接口
    private PersonalAppInterface personalAppInterface = SourceClientFactory
            .getAppServiceClient(PersonalAppInterface.class,"app/personal");
    
    	......    
        // 调用app层服务
        CustomerAndAccountList customerAndAccountList = this.personalAppInterface.getCustomerAndAccountList(customerId);
		......
    }

进阶要点

  • App层提供给Source层调用的接口,就是采用Biz-SIP平台规范的OpenAPI调用接口。

3、App层的PersonalAppInterface接口类

在上面的XmlController代码中,App服务调用接口在申请时,会要求填入App层的服务接口类PersonalAppInterface,这是在App层定义的,约定了能被Source层调用的App服务接口,如下所示:

public interface PersonalAppInterface {
    public CustomerAndAccountList getCustomerAndAccountList(String customerId);
    public List<Account> getAccountListByCustomerId(String customerId);
    public Customer getCustomer(String customerId);
    public BizMessage send2Payment1(Object message) throws BizException;
    public BizMessage send2Payment2(String tranMode, String tranCode, Object message) throws BizException;
    public Customer getCustomerAndSaf2Payment2(String tranMode, String customerId) throws BizException;
    public Account payout(String accountId,long amount);
    public void payoutForward(String tranMode,String accountId,long amount) throws BizException;
    public void payoutForwardCompensate(JSONObject jsonObject) throws BizException;
    public void payoutBackward(String tranMode,String accountId,long amount) throws BizException;
    public void payoutBackwardCompensate(JSONObject jsonObject) throws BizException;
}

进阶要点

  • App服务的接口,除了本节介绍的采用由开发者定义Java接口类以外,还可以统一采用AppBeanInterface接口类,AppBeanInterface接口类是采用平台标准JSON对象作为调用和返回参数,开发者继承AppBeanInterface接口后实现process()接口即可。
  • App层可以设置Source层调用服务的消息校验,支持域级和服务级的消息校验定义。

4、App层的PersonalAppService类

PersonalAppService类是上面PersonalAppInterface的具体实现类,服务接口是在类中具体实现的,主要是对Sink层的服务进行服务编排,如下所示:

@Service
public class PersonalAppService implements PersonalAppInterface {
    private AccountSinkInterface accountSinkInterface = AppClientFactory
            .getSinkClient(AccountSinkInterface.class,"account-sink");
    private CustomerSinkInterface customerSinkInterface = AppClientFactory
            .getSinkClient(CustomerSinkInterface.class,"customer-sink");
    private BizMessageInterface payment1SinkInterface = AppClientFactory
            .getSinkClient(BizMessageInterface.class,"payment1-sink");
    private BizMessageInterface payment2SinkInterface = AppClientFactory
            .getSinkClient(BizMessageInterface.class,"payment2-sink");
    private PersonalAppInterface personalAppDelayInterface = AppClientFactory
            .getDelayAppServiceClient(PersonalAppInterface.class,"app/personal",
                    0,1000,2000,4000,8000,16000,32000);

    @Override
    public CustomerAndAccountList getCustomerAndAccountList(String customerId) {
        Customer customer = this.customerSinkInterface.getCustomer(customerId);
        List<Account> accountList = this.accountSinkInterface.getAccountListByCustomerId(customerId);
        CustomerAndAccountList customerAndAccountList = new CustomerAndAccountList();
        customerAndAccountList.setCustomer(customer);
        customerAndAccountList.setAccountList(accountList);
        return customerAndAccountList;
    }
    ......
}

进阶要点

  • 在App服务中可以调用延迟服务,延迟服务能实现服务调用的自定义调用次数和重试间隔时间。
  • App层可以打开交易日志服务,根据设置的日志级别,会将交易成功、交易延迟调用、交易失败的状态日志,通过RabbitMQ队列发送给开发者应用,进行各种事后处理。

5、PersonalAppService调用Sink层服务

PersonalAppService类在代码中会申请Sink层服务的调用接口,在申请调用接口时,会采用Sink层封装好的Sink服务Interface接口类:

@Service
public class PersonalAppService implements PersonalAppInterface {
    private CustomerSinkInterface customerSinkInterface = AppClientFactory
            .getSinkClient(CustomerSinkInterface.class,"customer-sink");
    	......
        Customer customer = this.customerSinkInterface.getCustomer(customerId);
		......
}

进阶要点

  • 调用Sink层服务,除了支持普通的rest同步调用外(本节是采用rest同步调用),还支持rabbitmq异步调用(App服务无需等待返回结果)。

6、Sink层的CustomerSinkInterface接口类

在上面的PersonalAppService类代码中,Sink服务调用接口在申请时,会要求填入Sink层的服务接口类CustomerSinkInterface,这是在Sink层定义的,约定了能被App层调用的Sink服务接口,如下所示:

public interface CustomerSinkInterface {
    public Customer getCustomer(String customerId);
}

进阶要点

  • Sink层的内置标准服务接口,除了本节介绍的采用由开发者定义Java接口类以外,还可以统一采用JSONObjectSinkBeanInterface接口或SinkBeanInterface接口,开发者继承JSONObjectSinkBeanInterface接口或SinkBeanInterface接口后实现process()接口即可。JSONObjectSinkBeanInterface接口是采用平台标准JSON对象作为调用和返回参数,SinkBeanInterface接口是采用byte[]作为调用和返回参数(Biz-SIP平台会根据Sink端口定义的消息类型,自动实现byte[]字节流和平台JSON对象之间的消息打包和消息解包)。
  • 开发者也可以重写Sink服务相关的RestController类,在RestController类中直接获得当前Sink端口的格式转换器(Converter.getSinkConverter())和通讯适配器(Connector.getSinkConnector()),直接调用消息打包、消息解包,以及按指定通讯方式和第三方服务进行通讯适配,以实现更为灵活的服务逻辑。

7、Sink层的CustomerSinkService类

CustomerSinkService类是上面的CustomerSinkInterface接口的实现类,具体的Sink服务业务逻辑是在这个类中实现的:

@Service
public class CustomerSinkService implements CustomerSinkInterface {
    @Autowired
    private CustomerService custmerService;

    @Override
    public Customer getCustomer(String customerId) {
        Customer customer = this.custmerService.getById(customerId);
        return customer;
    }
}

Biz-SIP网站:http://bizsip.bizmda.com
Gitee代码库:https://gitee.com/szhengye/biz-sip

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值