| 🐉 Guava | 🐉 应用程序开发框架_生产力必备Flutter |
|---|
# 或许是实现重试最优雅的姿势
Guava Retrying是一个灵活方便的重试组件,包含了多种的重试策略,而且扩展起来非常容易。
- 如果抛出 IOException 则重试,如果返回结果为
null或者等于 2 则重试,固定等待时长为 300 ms,最多尝试 3 次
Callable<Integer> task = new Callable<Integer>() {
@Override
public Integer call() throws Exception {
return 2;
}
};
Retryer<Integer> retryer = RetryerBuilder.<Integer>newBuilder()
.retryIfResult(Predicates.<Integer>isNull())
.retryIfResult(Predicates.equalTo(2))
.retryIfExceptionOfType(IOException.class)
.withStopStrategy(StopStrategies.stopAfterAttempt(3))
.withWaitStrategy(WaitStrategies.fixedWait(300, TimeUnit.MILLISECONDS))
.build();
try {
retryer.call(task);
} catch (ExecutionException e) {
e.printStackTrace();
} catch (RetryException e) {
e.printStackTrace();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
- 出现异常则执行重试,每次任务执行最长执行时间限定为 3 s,重试间隔时间初始为 3 s,最多重试 1 分钟,随着重试次数的增加每次递增 1 s,每次重试失败,打印日志;
@Override
public Integer call() throws Exception {
return 2;
}
};
Retryer<Integer> retryer = RetryerBuilder.<Integer>newBuilder()
.retryIfException()
.withStopStrategy(StopStrategies.stopAfterDelay(30,TimeUnit.SECONDS))
.withWaitStrategy(WaitStrategies.incrementingWait(3, TimeUnit.SECONDS,1,TimeUnit.SECONDS))
.withAttemptTimeLimiter(AttemptTimeLimiters.<Integer>fixedTimeLimit(3,TimeUnit.SECONDS))
.withRetryListener(new RetryListener() {
@Override
public <V> void onRetry(Attempt<V> attempt) {
if (attempt.hasException()){
attempt.getExceptionCause().printStackTrace();
}
}
})
.build();
try {
retryer.call(task);
} catch (ExecutionException e) {
e.printStackTrace();
} catch (RetryException e) {
e.printStackTrace();
}
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
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
# 核心逻辑
long startTime = System.nanoTime();
for (int attemptNumber = 1; ; attemptNumber++) {
Attempt<V> attempt;
try {
// 执行成功
V result = attemptTimeLimiter.call(callable);
attempt = new ResultAttempt<V>(result, attemptNumber, TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime));
} catch (Throwable t) {
// 执行失败
attempt = new ExceptionAttempt<V>(t, attemptNumber, TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime));
}
// 监听器处理
for (RetryListener listener : listeners) {
listener.onRetry(attempt);
}
// 是否符合终止策略
if (!rejectionPredicate.apply(attempt)) {
return attempt.get();
}
// 是否符合停止策略
if (stopStrategy.shouldStop(attempt)) {
throw new RetryException(attemptNumber, attempt);
} else {
// 计算下次重试间隔时间
long sleepTime = waitStrategy.computeSleepTime(attempt);
try {
blockStrategy.block(sleepTime);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RetryException(attemptNumber, attempt);
}
}
}
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
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
# 依赖引入
<dependency>
<groupId>com.github.rholder</groupId>
<artifactId>guava-retrying</artifactId>
<version>2.0.0</version>
</dependency>
// 默认的guava中也有包含。
1
2
3
4
5
6
2
3
4
5
6
# 主要接口介绍
- Attempt:一次执行任务;
- AttemptTimeLimiter:单次任务执行时间限制(如果单次任务执行超时,则终止执行当前任务);
- BlockStrategies:任务阻塞策略(通俗的讲就是当前任务执行完,下次任务还没开始这段时间做什么……),默认策略为:BlockStrategies.THREAD_SLEEP_STRATEGY 也就是调用 Thread.sleep(sleepTime);
- RetryException:重试异常;
- RetryListener:自定义重试监听器,可以用于异步记录错误日志;
- StopStrategy:停止重试策略,提供三种:
- StopAfterDelayStrategy :设定一个最长允许的执行时间;比如设定最长执行10s,无论任务执行次数,只要重试的时候超出了最长时间,则任务终止,并返回重试异常RetryException;
- NeverStopStrategy :不停止,用于需要一直轮训知道返回期望结果的情况;
- StopAfterAttemptStrategy :设定最大重试次数,如果超出最大重试次数则停止重试,并返回重试异常;
- WaitStrategy:等待时长策略(控制时间间隔),返回结果为下次执行时长:
- FixedWaitStrategy:固定等待时长策略;
- RandomWaitStrategy:随机等待时长策略(可以提供一个最小和最大时长,等待时长为其区间随机值)
- IncrementingWaitStrategy:递增等待时长策略(提供一个初始值和步长,等待时间随重试次数增加而增加)
- ExponentialWaitStrategy:指数等待时长策略;
- FibonacciWaitStrategy :Fibonacci 等待时长策略;
- ExceptionWaitStrategy :异常时长等待策略;
- CompositeWaitStrategy :复合时长等待策略;
# Guice
Google开源的一个依赖注入类库Guice,相比于Spring IoC来说更小更快。Elasticsearch大量使用了Guice
# Guice概述
- Guice是Google开源的依赖注入类库,通过Guice减少了对工厂方法和new的使用,使得代码更易交付、测试和重用;
- Guice可以帮助我们更好地设计API,它是个轻量级非侵入式的类库;
- Guice对开发友好,当有异常发生时能提供更多有用的信息用于分析
# 谷歌推出新提案Portals:Web上的无缝跳转体验
一项名为 Portals 的 Web 平台 API 新提案,可以让用户在浏览网站时提升不同页面间跳转的流畅体验,从而帮助实现这一目标
# Portals带来了哪些内容
单页应用程序(SPA)提供了很好的页面过渡效果,但代价是更高的构建复杂性。多页面应用程序(MPA)的构建更容易一些,但结果会导致页面之间跳转时屏幕显示空白内容
Portals 则取两者所长:同时具备 MPA 的低复杂性和 SPA 的无缝过渡效果。可以将它们视为一个<iframe>,其中可以嵌入内容。但与<iframe>不同,它们还具有跳转到其中内容上的功能。
# 在Chrome Canary中试用Portals
要在 Chrome Canary 中试用 Portals,只需启用一个实验性标志:
chrome://flags/#enable-portals
让我们来看一个基本的例子。
// 用维基百科页面创建一个 portal,然后嵌入它。
// (就像一个 iframe)。你也可以使用<portal>标志。
portal = document.createElement('portal');
portal.src = 'https://en.wikipedia.org/wiki/World_Wide_Web';
portal.style = '...';
document.body.appendChild(portal);
// 用户触碰预览时(嵌入的 portal):
// 播放漂亮的动画,例如展开……
// 实际跳转完成后动画结束。
portal.activate();
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# 大型微服务系统管理工具,Istio 1.4.3 发布
Istio 是一个由谷歌、IBM 与 Lyft 共同开发的开源项目,旨在提供一种统一化的微服务连接、安全保障、管理与监控方式。
# 作为一个Java开发你应该试一试Jib,打包上传到docker
演示如何将Spring Boot 应用打成镜像并上传到Dockerhub仓库
以Maven工程为例,我们只需要在pom.xml中引入Jib Maven 插件。默认情况下Jib会把我们打好的镜像上传到Google的gcr.io仓库,实际中我们会把打好的镜像上传到私有仓库,所以我们要加一些个性化配置。这里我以dockerhub仓库为例添加一些个性化配置
<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>jib-maven-plugin</artifactId>
<version>2.4.0</version>
<configuration>
<!-- 相当于 Dockerfile 中的 FROM -->
<from>
<image>amazoncorretto:8</image>
</from>
<to>
<!--构建镜像名称,这里我使用maven中定义的项目名称-->
<image>daxus/${project.name}</image>
<!--私有仓库的账号密码-->
<auth>
<username>felordcn</username>
<password>yourpassword</password>
</auth>
<!--Docker 镜像的 tag 这里使用maven定义的版本号-->
<tags>
<tag>
${project.version}
</tag>
</tags>
</to>
</configuration>
</plugin>
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
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
然后在项目根目录执行mvn clean compile jib:build就可以了。
# Zxing生成带logo的二维码下面放文字
public static BufferedImage createWithSize(Integer qrCodeSize, String content) throws Exception {
Hashtable<EncodeHintType, Object> hints = new Hashtable<>();
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
hints.put(EncodeHintType.CHARACTER_SET, CHARSET);
int size = Objects.isNull(qrCodeSize) ? QRCODE_SIZE : qrCodeSize;
// 二维码与图片边距
// hints.put(EncodeHintType.MARGIN, 1);
BitMatrix bitMatrix = new QRCodeWriter().encode(content,
BarcodeFormat.QR_CODE, size, size, hints);
//deleteWhite(bitMatrix);
// 简化生成二维码逻辑,尽量使用现成方法-20201019
return MatrixToImageWriter.toBufferedImage(bitMatrix);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
# 生成二维码时获取文字的长度
Graphics2D outg = outImage.createGraphics();
outg.setFont(new Font("微软雅黑", Font.PLAIN, 18));
//文字长度
int strWidth = outg.getFontMetrics().stringWidth(words);
//总长度减去文字长度的一半 (居中显示)
int wordStartX=(WIDTH - strWidth) / 2;
1
2
3
4
5
6
2
3
4
5
6
# app
| 名称 | id |
|---|---|
| 默沙东诊疗手册 | com.msd.consumerChinese |
| 云闪付 | com.unionpay |
| 支付宝 | com.eg.android.AlipayGphone |
| 钱迹 | com.mutangtech.qianji |
| 淘宝 | com.taobao.taobao |
| 淘特 | com.taobao.litetao |
| 淘宝Lite(虚假嫌疑) | com.taobao.htao.android |
| 京东 | com.jingdong.app.mall |
| 今日头条 | com.ss.android.article.news |
| 老王VPN Lite | com.trustyourself |
| 老王VPN | com.sticktoit |
| setupVPN | com.setupvpn.main |
| 微信读书 | com.tencent.weread |
| 微信 | com.tencent.mm |
| 高德地图 | com.autonavi.minimap |
| 谷歌地图 | com.google.android.apps.maps |