怎样用此列表来排序彼列表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
private List<TagGroup> reorder(Long id, List<TagGroup> entities) {
final AccountSettings accountSettings = getAccountSetting(
id);
final List<Long> tagGroupOrders = accountSettings.getTagGroupOrders();
// 根据 tagGroupOrders 里提供的 tagGroupId 对 entities 排序
if (CollectionUtils.isNotEmpty(tagGroupOrders)) {
entities.sort((o1, o2) -> {
int index1 = tagGroupOrders.indexOf(o1.getTagGroupId());
int index2 = tagGroupOrders.indexOf(o2.getTagGroupId());
// 不对没有出现在列表里的 tagGroup 进行排序
if (index1 == -1 || index2 == -1) {
return sortByModifiedTime(o1, o2);
}
return index1 - index2;
});
}
// 还有一种潜在的排序方法是在这里加一个 else 分支,只对 modified time 进行排序

// 返回排序后的结果
return entities;
}

private static int sortByModifiedTime(TagGroup o1, TagGroup o2) {
final long time1 = o1.getLastModifiedTime().getTime();
final long time2 = o2.getLastModifiedTime().getTime();
if (time1 < time2) {
return -1;
} else if (time1 > time2) {
return 1;
} else {
return 0;
}
}

怎样每次生成一把锁实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
@Slf4j
@Component
@Scope("prototype")
public class LockRunner {

private RedissonClient redissonClient;

/**
* 私有构造器
*/
@Autowired
public LockRunner(RedissonClient redissonClient) {
this.redissonClient = redissonClient;
}

@WithSpan
public void runInLock(@SpanAttribute("lockConfig") LockKey lockKeyConfig, Runnable runnable) {
final String lockKey = lockKeyConfig.getLockKey();
RLock lock = redissonClient.getLock(lockKey);
// 新的锁是无限锁模式,只要锁的key包含细颗粒的id(手机号、线索id、呼叫id)就不会超时有问题
lock.lock();
try {
runnable.run();
} finally {
unlock(lock);
}
}

@WithSpan
public <V> V callInLock(@SpanAttribute("lockConfig") LockKey lockKeyConfig, Callable<V> callable) {
final String lockKey = lockKeyConfig.getLockKey();
RLock lock = redissonClient.getLock(lockKey);
// 新的锁是无限锁模式,只要锁的key包含细颗粒的id(手机号、线索id、呼叫id)就不会超时有问题
lock.lock();
try {
return callable.call();
} catch (Exception e) {
throw new SystemInternalException("callable.call()失败:" + e.getMessage(), e);
} finally {
unlock(lock);
}
}

private void unlock(RLock lock) {
log.info("unlock for: {}", lock.getName());
lock.unlock();
}
}

@Component
public class LockRunnerFactory {

private final ApplicationContext applicationContext;

@Autowired
public LockRunnerFactory(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}

public LockRunner createLockRunner() {
return applicationContext.getBean(LockRunner.class);
}
}

一个更好的设计是去掉@Scope("prototype")LockRunnerFactoryLockRunner的可变状态都被参数化了,所有最好的设计实际上是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
@Data
public class LockConfig {

/**
* 锁的后缀
*/
public static final String LOCK_SUFFIX = "-lock";

/**
* 超时时间
*/
private final int expireSecs;

/**
* 真正的锁键
*/
private final String lockKey;

private LockConfig(final int expireSecs, final String lockKey) {
this.expireSecs = expireSecs;
this.lockKey = lockKey;
}

public LockConfig(final int expireSecs, final Object... objects) {
this(expireSecs, Joiner.on("-").join(objects) + LOCK_SUFFIX);
}
}

@Data
public class LockKey {

/**
* 锁的后缀
*/
public static final String LOCK_SUFFIX = "-lock";


/**
* 真正的锁键
*/
private final String lockKey;

public LockKey(final Object... objects) {
lockKey = Joiner.on("-").join(objects) + LOCK_SUFFIX;
}

}

在还原一个字段的时候,怎么确定它有没有被修改过?

一个字段是 ownerId。它曾经是1,无意之中被设置为0,能不能恢复为1?
假设有另一个字段为 ownerName,有意设置 ownerId 的时候,一定会清空 ownerName。则可以做这样的比对:

1
2
3
if (owner == 0 && StringUtils.isNotBlank(ownerName)) {
owner = 1;
}

使用一个特定参数来排除某个 jar

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// 这个配置交给 service 层的那个 fileTree 来做也可以
// 引入本地的 lib
def jars = fileTree(dir: 'addtionnallib', include: ['*.jar'])

jars.each { File file ->
println("jars:${file}")
}

/*
* 这个配置会被在底层service层再执行一次,为了以后有人改错,在这里再做一次排除这里虽然是在根部做这个配置,但实质上却只读命令执行目录的 addtionnallib
* 下面这一段 直到 println留在这里的意义是:以防有一天构建模块不再在底层某一module,而它又需要差异化地使用 addtionnallib 式的 jar 时
*
* 不能这样使用
* ext {
* excludeHighJar = false
* }
* ext.excludeHighJar = false 必须写在这里才能被覆写
*/
ext.excludeHighJar = false
// 需要激活这个功能的项目的流水线参数: ../../gradlew clean build -x test -PexcludeHighJar=true
ext.excludeHighJar = project.hasProperty('excludeHighJar') ? project.getProperty('excludeHighJar') : false

if (excludeHighJar && excludeHighJar.trim()) {
// ${excludeHighJar}
jars = jars.minus(file("addtionnallib/a.jar"))
} else {
// 默认情况下排除 fat jar
jars = jars.minus(file("addtionnallib/a.fat.jar"))
}
api files(jars)
println "Excluding jar: ${excludeHighJar}"