function showImg(url) {
var frameid = ‘frameimg’ + Math.random();
window.img = ‘window.onload = function() { parent.document.getElementById(” + frameid + ”).height = document.getElementById(‘img’).height+’px’; }’;
document.write(”);
}
本文首发于泊浮目的专栏: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<InstanceOfferingInventory>() { @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的放入来自系统启动时利用反射所做的一个行为。因此并不会影响使用时的性能。