资讯专栏INFORMATION COLUMN

ZStack源码剖析之核心库鉴赏——Defer

ymyang / 710人阅读

摘要:本文首发于泊浮目的专栏在语言中,有一个关键字叫做其作用是在函数前执行。一般有两种用法在该函数抛出异常时执行。在该函数返回前执行。这里的放入来自系统启动时利用反射所做的一个行为。因此并不会影响使用时的性能。

本文首发于泊浮目的专栏:https://segmentfault.com/blog...

在Go语言中,有一个关键字叫做defer——其作用是在函数return前执行。在ZStack中也有类似的工具类,让我们来看看吧。

演示代码
    private void handle(APICreateInstanceOfferingMsg msg) {
        APICreateInstanceOfferingEvent evt = new APICreateInstanceOfferingEvent(msg.getId());

        String type = msg.getType() == null ? UserVmInstanceOfferingFactory.type.toString() : msg.getType();
        InstanceOfferingFactory f = getInstanceOfferingFactory(type);

        InstanceOfferingVO vo = new InstanceOfferingVO();
        if (msg.getResourceUuid() != null) {
            vo.setUuid(msg.getResourceUuid());
        } else {
            vo.setUuid(Platform.getUuid());
        }
        HostAllocatorStrategyType allocType = msg.getAllocatorStrategy() == null ? HostAllocatorStrategyType
                .valueOf(HostAllocatorConstant.LEAST_VM_PREFERRED_HOST_ALLOCATOR_STRATEGY_TYPE) : HostAllocatorStrategyType.valueOf(msg.getAllocatorStrategy());
        vo.setAllocatorStrategy(allocType.toString());
        vo.setName(msg.getName());
        vo.setCpuNum(msg.getCpuNum());
        vo.setCpuSpeed(msg.getCpuSpeed());
        vo.setDescription(msg.getDescription());
        vo.setState(InstanceOfferingState.Enabled);
        vo.setMemorySize(msg.getMemorySize());
        vo.setDuration(InstanceOfferingDuration.Permanent);
        vo.setType(type);

        InstanceOfferingInventory inv = new SQLBatchWithReturn() {
            @Override
            @Deferred
            protected InstanceOfferingInventory scripts() {
                Defer.guard(() -> dbf.remove(vo));
                InstanceOfferingInventory inv = f.createInstanceOffering(vo, msg);
                acntMgr.createAccountResourceRef(msg.getSession().getAccountUuid(), vo.getUuid(), InstanceOfferingVO.class);
                tagMgr.createTagsFromAPICreateMessage(msg, vo.getUuid(), InstanceOfferingVO.class.getSimpleName());
                return inv;
            }
        }.execute();

        evt.setInventory(inv);
        bus.publish(evt);
        logger.debug("Successfully added instance offering: " + printer.print(inv));
    }

这段代码是ZStack ManageNode(简称MN)在接收到创建计算规格的请求后的处理逻辑,大致的逻辑即:

在DB中创建一条记录

添加当前账户与该计算规格的关联

创建相应的系统标签

回复该消息,并打印一行log

在这段代码中,我们可以看到在执行逻辑2、3时,这里做了一个Defer.guard(() -> dbf.remove(vo));,其作用是在执行下面的逻辑发生异常时执行,这样就移除了脏数据。

如何使用

Defer的使用方法也很简单,如果你要在某个函数使用它,在上面添加一个 @Deferred的Annotation,然后就可以在该函数内使用它了。

一般有两种用法:

Defer.guard:在该函数抛出异常时执行Runable。

Defer.defer:在该函数返回前执行。我们可以使用其释放局部锁。

为了避免不熟悉ZStack读者理解起来生涩,建议参考其Case在这里,我们将展现一个较为简单的case:

public class TestDefer1 {
    CLogger logger = Utils.getLogger(TestDefer1.class);
    int count = 0;

    @Before
    public void setUp() throws Exception {
    }


    @Deferred
    private void case1() {
        count++;
        Defer.guard(new Runnable() { //当捕捉到异常时,执行其中的匿名Runable语句
            @Override
            public void run() {
                count--;
            }
        });
        //抛出一个异常
        throw new CloudRuntimeException("Roll back count");
    }

    @Test(expected = CloudRuntimeException.class)
    public void test() {
        case1();
        Assert.assertEquals(0, count);
    }
}
实现

Defer的库非常的小。其本质通过对Spring提供的AOP和Java提供的ThreadLocal以及一个Stack数据结构进行封装:对于执行函数的当前线程存入一个Stack数据结构,每一个填写在Defer中的Runable都会被放入,之后根据调用的Defer的函数来决定其行为。

这里Runable的放入来自系统启动时利用反射所做的一个行为。因此并不会影响使用时的性能。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/25203.html

相关文章

  • ZStack源码剖析核心鉴赏——Defer

    摘要:本文首发于泊浮目的专栏在语言中,有一个关键字叫做其作用是在函数前执行。一般有两种用法在该函数抛出异常时执行。在该函数返回前执行。这里的放入来自系统启动时利用反射所做的一个行为。因此并不会影响使用时的性能。 本文首发于泊浮目的专栏:https://segmentfault.com/blog... 在Go语言中,有一个关键字叫做defer——其作用是在函数return前执行。在ZStac...

    DevWiki 评论0 收藏0
  • ZStack源码剖析核心鉴赏——ThreadFacade

    摘要:每个消息都会被一个线程消费,同时最大并发量为。然后提交一个任务到线程池中,这个任务的内容是从等待队列中取出一个,如果等待队列为空,则删除这个等待队列的。小结本文分析了的久经生产考验的核心组件线程池。 本文首发于泊浮目的专栏:https://segmentfault.com/blog... 前言 在ZStack中,最基本的执行单位不仅仅是一个函数,也可以是一个任务(Task。其本质实现...

    enali 评论0 收藏0
  • ZStack源码剖析二次开发——可扩展框架

    摘要:但在实际的二次开发中,这些做法未必能够完全满足需求。在源码剖析之核心库鉴赏一文中,我们了解到是的基础设施之一,同时也允许通过显示声明的方式来声明。同理,一些也可以使用继承进行扩展。 本文首发于泊浮目的专栏:https://segmentfault.com/blog... 前言 在ZStack博文-5.通用插件系统中,官方提出了几个较为经典的扩展方式。但在实际的二次开发中,这些做法未必...

    lolomaco 评论0 收藏0
  • ZStack源码剖析核心鉴赏——FlowChain

    摘要:下面将开始分析它的源码。仅仅定义了一个最小应有的行为。更好的选择由于该库是为定制而生,故此有一些防御性判断,源码显得略为。 本文首发于泊浮目的专栏:https://segmentfault.com/blog... 前言 在ZStack(或者说产品化的IaaS软件)中的任务通常有很长的执行路径,错误可能发生在路径的任意一处。为了保证系统的正确性,需提供一种较为完善的回滚机制——在ZSt...

    yintaolaowanzi 评论0 收藏0
  • ZStack源码剖析设计模式鉴赏——三驾马车

    摘要:但新增模块的结构却还是大致相同,此即是的经典设计模式这套模式也被开发者称为三驾马车。领域层定义负责表达业务概念,业务状态信息以及业务规则。 本文首发于泊浮目的专栏:https://segmentfault.com/blog... 前言 随着ZStack的版本迭代,其可以掌管的资源也越来越多。但新增模块的结构却还是大致相同,此即是ZStack的经典设计模式——这套模式也被开发者称为ZS...

    honhon 评论0 收藏0

发表评论

0条评论

ymyang

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<