可通过设置 ConfigDB 的 ServerConfig 的 "namespace.lock.switch"
为 "true"
开启。效果如下:
- 一次配置修改只能是一个人
- 一次配置发布只能是另一个人
也就是说,开启后,一次配置修改并发布,需要两个人。默认为 "false"
,即关闭。
NamespaceLock
com.ctrip.framework.apollo.biz.entity.NamespaceLock
,继承 BaseEntity 抽象类,Namespace Lock 实体。代码如下:
1 |
|
- 写操作 Item 时,创建 Namespace 对应的 NamespaceLock 记录到 ConfigDB 数据库中,从而记录配置修改人。
namespaceId
字段,Namespace 编号,指向对应的 Namespace 。- 该字段上有唯一索引。通过该锁定,保证并发写操作时,同一个 Namespace 有且仅有创建一条 NamespaceLock 记录。
加锁与解锁的过程
"限制修改人
在 apollo-adminservice
项目中,在 aop
模块中,通过 Spring AOP 记录 NamespaceLock ,从而实现锁定 Namespace ,限制修改人。
1. @PreAcquireNamespaceLock
com.ctrip.framework.apollo.adminservice.aop.@PreAcquireNamespaceLock
,注解,标识方法需要获取到 Namespace 的 Lock 才能执行。
1 | (ElementType.METHOD) |
目前添加了 @PreAcquireNamespaceLock
注解的方法如下图:
2. NamespaceAcquireLockAspect
com.ctrip.framework.apollo.adminservice.aop.NamespaceAcquireLockAspect
,获得 NamespaceLock 切面。
1. 定义切面
1 |
|
@Aspect
注解,标记为表面类。@Before
注解,标记切入执行方法前。- 调用
#acquireLock(...)
方法,尝试锁定。
2. acquireLock
1 | void acquireLock(String appId, String clusterName, String namespaceName, String currentUser) { |
- 发生 DataIntegrityViolationException 异常,说明保存 NamespaceLock 对象失败,由于唯一索引
namespaceId
冲突,调用NamespaceLockService#findLock(NamespaceLock)
方法,获得最新的 NamespaceLock 对象。 - 调用
#checkLock(namespace, namespaceLock, currentUser)
方法,校验锁定人是否是当前管理员。 - 当
NamespaceLock.dataChangeCreatedBy
不是当前管理员时,抛出 BadRequestException 异常,从而实现限制修改人。
NamespaceUnlockAspect
com.ctrip.framework.apollo.adminservice.aop.NamespaceUnlockAspect
,释放 NamespaceLock 切面。在配置多次修改,恢复到原有状态( 即最后一次 Release 的配置) 。因此,NamespaceUnlockAspect 的类注释如下:
unlock namespace if is redo operation.
For example: If namespace has a item K1 = v1
- First operate: change k1 = v2 (lock namespace)
- Second operate: change k1 = v1 (unlock namespace)
1. 定义切面
1 |
|
@Aspect
注解,标记为表面类。@After
注解,标记切入执行方法后。- 调用
#tryUnlock(...)
方法,尝试解锁。
2. tryUnlock
1 | private void tryUnlock(Namespace namespace) { |
#isModified(Namespace)
方法,若当前 Namespace 的配置恢复原有状态。NamespaceLockService#unlock(namespaceId)
方法,释放锁,即删除 NamespaceLock 。
限制发布人
发布配置时,调用 ReleaseService#publish(...)
方法时,在方法内部,会调用 #checkLock(Namespace namespace, boolean isEmergencyPublish, String operator)
方法,校验锁定人是否是当前管理员。代码如下:
1 | 1: private void checkLock(Namespace namespace, boolean isEmergencyPublish, String operator) { |
- 第 2 行:非紧急发布,可通过设置 PortalDB 的 ServerConfig 的
"emergencyPublish.supported.envs"
配置开启对应的 Env 们。例如,emergencyPublish.supported.envs = dev
。 - 第 6 至 8 行:当
NamespaceLock.dataChangeCreatedBy
是当前管理员时,抛出 BadRequestException 异常,从而实现限制修改人。
解锁
发布配置时,调用 ReleaseService#createRelease(...)
方法时,在方法内部,会调用 NamespaceLockService#unlock(namespaceId)
方法,释放 NamespaceLock 。代码如下:
1 | private Release createRelease(Namespace namespace, String name, String comment, |