技术阅读周刊第十一期

8e7f8fd63ca2050d0c9bb84b8c6a7ec8.png

技术阅读周刊,每周更新。

历史更新

  • 20231124:第七期

  • 20231201:第八期

  • 20231215:第十‍期

A Comprehensive guide to Spring Boot 3.2 with Java 21, Virtual Threads, Spring Security, PostgreSQL, Flyway, Caching, Micrometer, Opentelemetry, JUnit 5, RabbitMQ, Keycloak Integration, and More! (10/17) | by Jonathan Chevalier | Nov, 2023 | Medium

URL: https://medium.com/@jojoooo/exploring-a-base-spring-boot-application-with-java-21-virtual-thread-spring-security-flyway-c0fde13c1eca#551c

本文讲解了基于最新的 Spring Boot3.2 和 Java 21 所使用到的技术栈

数据库

数据库使用 Postgres15 和 flyway 来管理数据库 schema 的迁移。8fbbd8a4bc2deed561ad191d89cb0a27.png

异常处理

Spring6 实现了新的 RFC9457规范,实现以下接口:

@Slf4j
@ControllerAdvice
@RequiredArgsConstructor
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {// Process @Valid@Overrideprotected ResponseEntity<Object> handleMethodArgumentNotValid(@NonNull final MethodArgumentNotValidException ex,@NonNull final HttpHeaders headers,@NonNull final HttpStatusCode status,@NonNull final WebRequest request) {log.info(ex.getMessage(), ex);final List<ApiErrorDetails> errors = new ArrayList<>();for (final ObjectError err : ex.getBindingResult().getAllErrors()) {errors.add(ApiErrorDetails.builder().pointer(((FieldError) err).getField()).reason(err.getDefaultMessage()).build());}return ResponseEntity.status(BAD_REQUEST).body(this.buildProblemDetail(BAD_REQUEST, "Validation failed.", errors));}private ProblemDetail buildProblemDetail(final HttpStatus status, final String detail, final List<ApiErrorDetails> errors) {final ProblemDetail problemDetail =ProblemDetail.forStatusAndDetail(status, StringUtils.normalizeSpace(detail));// Adds errors fields on validation errors, following RFC 9457 best practices.if (CollectionUtils.isNotEmpty(errors)) {problemDetail.setProperty("errors", errors);}return problemDetail;}
{"type": "about:blank","title": "Bad Request","status": 400,"detail": "Validation failed.","instance": "/management/companies","errors": [{"pointer": "name","reason": "must not be blank"},{"pointer": "slug","reason": "must not be blank"}]
}

应用异常

@Getter
public class RootException extends RuntimeException {@Serial private static final long serialVersionUID = 6378336966214073013L;private final HttpStatus httpStatus;private final List<ApiErrorDetails> errors = new ArrayList<>();public RootException(@NonNull final HttpStatus httpStatus) {super();this.httpStatus = httpStatus;}public RootException(@NonNull final HttpStatus httpStatus, final String message) {super(message);this.httpStatus = httpStatus;}
}@ExceptionHandler(RootException.class)
public ResponseEntity<ProblemDetail> rootException(final RootException ex) {log.info(ex.getMessage(), ex);// Uses default message, can be adapted to use ex.getMessage().final ProblemDetail problemDetail =this.buildProblemDetail(ex.getHttpStatus(), API_DEFAULT_REQUEST_FAILED_MESSAGE, ex.getErrors());return ResponseEntity.status(ex.getHttpStatus()).body(problemDetail);
}{"type": "about:blank","title": "Internal Server Error","status": 500,"detail": "Request failed.","instance": "/back-office/hello-world"
}

异常降级

@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ExceptionHandler(Throwable.class)
public ProblemDetail handleAllExceptions(final Throwable ex, final WebRequest request) {log.warn(ex.getMessage(), ex);this.slack.notify(format("[API] InternalServerError: %s", ex.getMessage()));return this.buildProblemDetail(HttpStatus.INTERNAL_SERVER_ERROR, API_DEFAULT_ERROR_MESSAGE);
}{"type": "about:blank","title": "Internal Server Error","status": 500,"detail": "Something went wrong. Please try again later or enter in contact with our service.","instance": "/back-office/hello-world"
}

当有无法处理的异常时,就需要配置一个兜底的异常。

缓存

<dependency>  <groupId>org.springframework.boot</groupId>  <artifactId>spring-boot-starter-cache</artifactId>  
</dependency>
public interface CompanyRepository extends JpaRepository<Company, Long> {String CACHE_NAME = "company";@NonNull@Cacheable(value = CACHE_NAME, key = "{'byId', #id}")@OverrideOptional<Company> findById(@NonNull Long id);@Cacheable(value = CACHE_NAME, key = "{'bySlug', #slug}")Optional<Company> findBySlug(String slug);@Caching(evict = {@CacheEvict(value = CACHE_NAME, key = "{'byId', #entity.id}"),@CacheEvict(value = CACHE_NAME, key = "{'bySlug', #entity.slug}"),})@Override<S extends Company> @NonNull S save(@NonNull S entity);/** This cache implementation is only valid if the table is not* frequently updated since it will clear the cache at every update operation* If you want to be more performant you can use something like https://github.com/ms100/cache-as-multi* */@NonNull@CacheEvict(cacheNames = CACHE_NAME, allEntries = true)@Override<S extends Company> List<S> saveAll(@NonNull Iterable<S> entities);@Caching(evict = {@CacheEvict(value = CACHE_NAME, key = "{'byId', #entity.id}"),@CacheEvict(value = CACHE_NAME, key = "{'bySlug', #entity.slug}"),})@Overridevoid delete(@NonNull Company entity);/** This cache implementation is only valid if the table is not* frequently updated since it will clear the cache at every delete operation* If you want to be more performant you can use something like https://github.com/ms100/cache-as-multi* */@CacheEvict(cacheNames = CACHE_NAME, allEntries = true)@Overridevoid deleteAll(@NonNull Iterable<? extends Company> entities);
}

Spring 提供了标准的缓存接口,即便是后续需要切换到 Redis,使用的 API 和注解都不会发生改变。

线程

Java21 后支持了虚拟线程,几乎可以无限的实现线程,在 Spring Boot 3.2 需要单独开启。

spring.threads.virtual.enabled

可观测性

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency><groupId>io.micrometer</groupId><artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
spring:endpoints:web:exposure:include: info, health, prometheus, metrics
47a2b41e5f02f32403aef1c66fed76df.png
image.png

注意在生成环境不要暴露管理 API

Trace

<dependency><groupId>io.micrometer</groupId><artifactId>micrometer-tracing-bridge-otel</artifactId>
</dependency>
<dependency><groupId>net.ttddyy.observation</groupId><artifactId>datasource-micrometer-spring-boot</artifactId><version>${datasource-micrometer.version}</version>
</dependency>
<dependency><groupId>io.opentelemetry</groupId><artifactId>opentelemetry-exporter-otlp</artifactId><version>${opentelemetry-exporter-otlp.version}</version>
</dependency>

同步请求的时候每个请求都会带上 traceIdspanId ,如果是异步请求时候需要配置:spring.reactor.context-propagation=true

如果使用 @Async时:

@Configuration
public class TaskExecutorConfig {/** Override default SimpleAsyncTaskExecutor to provide context propagation in @Async function* */@Beanpublic TaskExecutor simpleAsyncTaskExecutor() {final SimpleAsyncTaskExecutor taskExecutor = new SimpleAsyncTaskExecutor();taskExecutor.setTaskDecorator(new ContextPropagatingTaskDecorator());return taskExecutor;}
}

本地测试时候可以使用 Otel Desktop Viewer

management:  tracing:sampling:probability: 1otlp:tracing:endpoint: http://localhost:4317
ef844879e1f1c20a055ea79efda76353.png
image.png

Rust Vs Go: A Hands-On Comparison

URL: https://www.shuttle.rs/blog/2023/09/27/rust-vs-go-comparison

动手比较 Rust 和 Go

664e13eacef4fc883db9001d55a29730.png
image.png

本文是通过编写一个 web 服务来进行比较的。

  • Go 更加简单易学,同时标准库非常强大,只需要配合 gin+sqlx 这两个第三方库就能实现一个 web 服务

  • Rust也可以快速的构建一个安全的 web 服务,但需要依赖许多第三方库,比如http/JSON/模板引擎/时间处理等

  • 但 Rust 在异常处理方面心智负担更低,代码更容易阅读。

  • 如果是一个初创小团队,使用 Go 的上手难度确实更低;

  • 但如果团队愿意花时间投入到 Rust 中,结合他出色的错误处理,和强大的编译检查,长时间来看会得到更好的效果。

为什么要使用 Go 语言?Go 语言的优势在哪里?- 知乎

URL: https://www.zhihu.com/question/21409296/answer/1040884859

图文并茂,讲解了 G-M-P 各自之间的关系,以及调度模型。

76e96da497713fbb4ba7b9eb41b941e4.png
image.png
  • G: Goroutine,用户创建的协程,图中搬运的砖头。

  • M: Machine,OS 内核的线程的抽象,代表真正执行的资源;对应到就是图中的地鼠,地鼠不能用户直接创建;得是砖头 G 太多,地鼠 M 本身太少,同时还有空闲的小车 P,此时就会从其他地方借一些地鼠 M 过来直到把小车 P 用完为止。

  • P: Processor 处理器,G 只有绑定到 P 才能被调度;P 是图中的小车,由用户设置的 GoMAXPROCS 决定小车的数量。

文章链接:

  • https://blog.canopas.com/golang-14-shorthand-tricks-you-might-not-know-8d8d21954c49

  • https://medium.com/@jojoooo/exploring-a-base-spring-boot-application-with-java-21-virtual-thread-spring-security-flyway-c0fde13c1eca#551c

  • https://www.zhihu.com/question/21409296/answer/1040884859

    往期推荐

    如何给开源项目发起提案

    如何编写一个 Pulsar Broker Interceptor 插件

    老炮新作,大一统的监控探针采集器 cprobe 开源了

    五分钟 k8s 实战-滚动更新与优雅停机

    d4ceee0b26d867abb8ade8c8ab8baf76.gif

    点分享

    2249a8efdc814b1c3e43dd7013c2d634.gif

    点收藏

    ee977054406151dbad443535ad9fe81e.gif

    点点赞

    4f6f0a90d7375be403e0397b2a939ee6.gif

    点在看

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/493550.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据智能是大数据的未来

来源&#xff1a;中国信息产业网 近日&#xff0c;两家大数据领域的代表性企业Cloudera和Hortonworks宣布了它们相对平等的合并&#xff0c;宣称新公司将创建世界领先的下一代数据平台并提供业界首个企业数据云&#xff0c;这令很多人感到意外&#xff0c;大数据的未来何去何从…

利用GAN原始框架生成手写数字

这一篇GAN文章只是让产生的结果尽量真实&#xff0c;还不能分类。 本次手写数字GAN的思想&#xff1a; 对于辨别器&#xff0c;利用真实的手写数字&#xff08;真样本&#xff0c;对应的标签为真标签&#xff09;和随机噪声经过生成器产生的样本&#xff08;假样本&#xff0…

DL也懂纹理吗——图像的纹理特征

工作中遇到一个问题&#xff1a;对于同一场景&#xff0c;训练好的DL模型能把大部分样本分类准确&#xff0c;而对于少量负样本&#xff0c;DL会错分到另外一个对立的类中。错分的样本可以认为是难分的样本&#xff0c;但是我们还想知道这两种样本到底是哪里的差异导致DL做出了…

排序算法--(冒泡排序,插入排序,选择排序,归并排序,快速排序,桶排序,计数排序,基数排序)

一.时间复杂度分析 - **时间复杂度**&#xff1a;对排序数据的总的操作次数。反应当n变化时&#xff0c;操作次数呈现什么规律 - **空间复杂度**&#xff1a;算法在计算机内执行时所需要的存储空间的容量&#xff0c;它也是数据规模n的函数。 1.例题: 有一个字符串数组&…

肠里细菌“肚里蛔虫”:肠脑研究缘何越来越热

来源&#xff1a;科学网最懂你大脑的&#xff0c;可能不是“肚子里的蛔虫”&#xff0c;而是肠子里的细菌——肠道菌群对神经系统、心理和行为方面的影响正成为一个新兴热点领域。在日前举办的美国神经科学学会年会上&#xff0c;一张海报上的大脑切片显微镜图像显示&#xff0…

SVM原理与实战

先看线性可分问题。对于线性可分&#xff0c;其实感知机就可以解决。但是感知机只是找到一个超平面将数据分开&#xff0c;而这样的超平面可能是平行的无限多个&#xff0c;我们需要在这其中找到最优的一个。怎么衡量一个超平面是不是最优的呢&#xff0c;直观上讲&#xff0c;…

2014-01-01

一:HyperlinkButton点击后打开新窗口的方法 1,直接在界面中写这段代码就可以了: <HyperlinkButton NavigateUri"http://www.cnblogs.com/wsdj-ITtech/" Content"Click Me" TargetName"_blank" FontSize"28" Height"50"…

李飞飞高徒:斯坦福如何打造基于视觉的智能医院?

作者&#xff1a;Albert Haque、Michelle Guo来源&#xff1a;机器之心自 2009 年担任斯坦福人工智能实验室和视觉实验室的负责人&#xff0c;李飞飞在推动计算机视觉方面研究的同时&#xff0c;还密切关注 AI 医疗的发展。昨日&#xff0c;李飞飞离任斯坦福 AI 实验室负责人一…

tensorflow知识点

一.bazel编译tensorflow注意版本号: 在/tensorflow/tensorflow/configure.py 查看bazel版本号 https://github.com/tensorflow/tensorflow https://github.com/bazelbuild/bazel/releases?after0.26.1 https://tensorflow.google.cn/ 二&#xff0c;基础知识点 1.打印出…

eclipse中如何导入jar包

如图&#xff0c;首先右键点击项目&#xff0c;选择最下面的properties&#xff0c; 然后进去之后点击java build path&#xff0c;右边会出来4个选项卡&#xff0c;选择libraries&#xff0c; 这时候最右边会有多个选项&#xff0c;第一个add jars是添加项目文件中的jar包&…

线性-LR-softmax傻傻分不清楚

softmax 对于分类网络&#xff0c;最后一层往往是全连接层&#xff0c;如果是N分类&#xff0c;那么最终的全连接层有N个结点。很显然&#xff0c;每个节点对应一个类&#xff0c;该节点的权重越大&#xff0c;说明网络越倾向于认为输入样本属于该类。这其实就是Softmax的思想…

一图看懂国外智能网联汽车传感器产业发展!

来源&#xff1a;赛迪智库编辑&#xff1a;煜 佳未来智能实验室是人工智能学家与科学院相关机构联合成立的人工智能&#xff0c;互联网和脑科学交叉研究机构。未来智能实验室的主要工作包括&#xff1a;建立AI智能系统智商评测体系&#xff0c;开展世界人工智能智商评测&#…

深度学习中的信息论——交叉熵

信息量 可以说就信息量是在将信息量化。首先信息的相对多少是有切实体会的&#xff0c;有的人一句话能包含很多信息&#xff0c;有的人说了等于没说。我们还可以直观地感觉到信息的多少和概率是有关的&#xff0c;概率大的信息也相对低一些。为了量化信息&#xff0c;一个做法…

传统手工特征--opencv

一&#xff0c;颜色特征&#xff1a; 简单点来说就是将一幅图上的各个像素点颜色统计出来&#xff0c;适用颜色空间&#xff1a;RGB&#xff0c;HSV等颜色空间&#xff0c; 具体操作&#xff1a;量化颜色空间&#xff0c;每个单元&#xff08;bin&#xff09;由单元中心代表&…

特写李飞飞:她激励了人工智能的发展,更要给人工智能赋予人的价值

文 | MrBear 编辑 | 杨晓凡来源&#xff1a;雷锋网摘要&#xff1a;李飞飞无疑是人工智能界最响亮的名字之一。她既对机器学习领域的发展做出了杰出的贡献&#xff0c;也是普通大众眼中温和的人工智能技术宣扬者&#xff0c;还是谷歌这一科技巨头的人工智能技术领导人之一。WI…

Chap-4 Section 4.2.4 指令修正方式

对于X86平台下的ELF文件的重定位入口所修正的指令寻址方式只有两种&#xff1a;绝对近址32寻址和相对近址32寻址。 这两种指令修正方式每个被修正的位置的长度都为32位&#xff0c;即4个字节&#xff0c;而且都是近址寻址&#xff0c;不用考虑Intel的段间远址寻址。r_info成员的…

没见过女人的小和尚——SVDD

是的&#xff0c;即便是出生在山上的小和尚&#xff0c;从来没有下过山&#xff0c;没有见过女人&#xff0c;但是一旦有女施主上山&#xff0c;小和尚依然可以轻松地区分出眼前的人是如此不同。 传统的SVM是寻找一个超平面&#xff0c;而SVDD寻找的超平面更进一步&#xff0c…

解读GAN及其 2016 年度进展

作者&#xff1a;程程 链接&#xff1a;https://zhuanlan.zhihu.com/p/25000523 来源&#xff1a;知乎 著作权归作者所有。商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处。 GAN&#xff0c;全称为Generative Adversarial Nets&#xff0c;直译为生成式对抗网络…

全国首套中小学生人工智能教材在沪亮相

来源&#xff1a;网络大数据中小学 AI 教材正式亮相11 月 18 日&#xff0c;优必选与华东师范大学出版社共同发布了《AI 上未来智造者——中小学人工智能精品课程系列丛书》&#xff08;以下简称“AI 上未来智造者”丛书&#xff09;。据了解&#xff0c;该丛书根据教育部“义务…

numpy基础知识点

1. np.squeeze 一,np.squeeze """ np.squeeze 删除单维度的条 对多维度无效 """ import numpy as np anp.array([[1,2],[3,4],[4,5]]) print(a) print(a.shape) bnp.squeeze(a) print(b) ca.reshape(1,6,1) print(c) print(np.squeeze(c)) pri…