领域事件与Netty结合的一个使用场景与设计

        一个应用系统,分布有中心与区节点个环节,系统间由于中心与节点处理内外网关系,系统中要进行双向的通信需NAT穿透,简单选型使用了Soket通信,由节点主动上连中心,提供服务,并保存套接字。

        Netty是一个事件驱动,多线程的,支持多种协议与支持NIO的一个JAVA编写的Socket框架,使用Netty可以省去了很多开发中遇到的问题。

        系统应用架构上根据了DDD做为参考,领域层-中心的Server , 节点的Client, 定义为了两个聚合根,行为类型,动作起来需要组合不同的聚合跟实例进行相关业务逻辑操作。

        应用服务一层位于领域层之上,用于负责领域事件注册,事务控制的一个Facade层。

        项目中有这样的一个场景:

        中心Server通过一定机制,发送信令到对应的节点Client,节点Client接收到的信令进行相关操作(操作数据库,WebService请求),这些操作都均耗时耗资源,我们第一直观感觉是使用多线程解决,从而不阻塞Netty的相应InboundHandler在管道中进行下一个节点进行操作,项目中也确实是这样用了。:^)

        对于这个相关操作,关系到了数据库事务控制等这些问题,而节点在Client位于领域层,按照DDD的思路,这一类的操作应该交由应用服务的某个方法执行。但接入到信令的操作发生在领域层,而领域层并不能获取到上层应用服务接口,这促使了我在项目中选用了领域事件,进行事件发布。

        由应用服务层注册事件Subscriber,进行订阅,获取到领域事件后,交由同一层(应用服务)的服务接口进行操作。解决了不同层次依赖问题。

大致的思路,用些精简的伪代码表示:

准备领域事件的几个类

DomainEventPublisher事件发布器

public class DomainEventPublisher
{
    public void publish(DomainEvent event,ExecutorService execotor)
    {
        ...
        executor.execute(new Runnable(){
            public void run()
            {
                for(DomainEventSubscribe subscribe : this.subscribes)
                {
                    subscribe.handle(event);
                }
            }
        );
    }
    public void subscribe(DomainEventSubscribe subscribe){...}
}
DomainEvent 领域事件接口


public interface DomainEvent{}
DomainEventSubscriber 事件订阅者接口


public interface DomainEventSubscribe
{
    void handle(DomainEvent domainEvent);
}


定义领域层Client端

Client聚合根

public class Clent
{
    private DomainEventPublisher publiser;

    public void open()
    {
        // ...netty的api等
        
        //加入一个自定义的handler
        channel.pipeline().addLast( new AppHandler() );
    }

    public void close(){...}
    
    public void subscribe(DomainEventSubscribe subscribe)
    {
        this.publiser.subscribe(subscribe);
    }
}

AppHandler


public class AppHandler extends ChannelInboundHandler
{
    private DomainEventPublisher publisher;
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception
    {
        Signalling signalling = (Singalling) msg;
        String data = signalling.data();
        AppDomainEvent event = new AppDomainEvent(data);
        publisher.publish(event,ctx.channel().eventLoop());
        ...
    }
}
AppDomainEvent,我们实现的领域事件



public class AppDomainEvent implements DoaminEvent
{
    public AppDomainEvent(String data){this.data = data}

    public String data(){return data}
}



应用层

ClientApplicationService,创建Client的一些Facade接口


public class ClientApplicationService
{
    public void newClient(String clientId)
    {
        Client client = new Client(clientId);
        client.subscribe(  new AppDomainEventSubscriber() );
        return client;
    }
}
AppDoaminEventSubscriber订阅器



public class AppDomainEventSubscriber implements DomainEventSubscribe
{
    public void handle(DomainEvent event)
    {
        if(event.class.equals( AppDomainEvent.class ) )
        {
            AppDoaminEvent e = (AppDomainEvent) event;
            ApplicationRegister.otherApplicationService().do(e.data());
        }
    }
}

        注:ApplicationRegister.otherApplicationService()的意思是获取改领域层的其他应用服务,来进行对领域事件中带回来的data进行业务操作。

        以上便是偶在项目中的一个解决方案,希望有帮助


你可能感兴趣的:(领域事件)