A

image.png

内存还是没啥好炫耀的,下周要不集中把前几周的这些题分析一下

R

意外,看这篇吧,算是工作的一部分

这个记录一下是因为以前寻求这个知识点细节的时候,搜索的都是spring+boot+swagger,或者说有意无意的把swagger和openapi等同起来的,从历史的角度看,这种理解的简化并不过分,比如我们看一下对应主题的历史章节,但从知识的延续和更替角度来看,这种头脑中的思维印象带来的僵化,可能会对实际工作学习的流畅度带来影响

废话不多说了,否则成完成Share里面的view了,但这篇的link延展读下去都会有收获这个,不得不提

结构

一共11个章节,第一段overview和最后一段conclusion是八股文段落,但是介绍了一些背景信息和概述了一些重点功能,中间2-10共9个段落都是干货,实用主义同学的最爱,第10节 算是个彩蛋,算是给厌恶Java?的同学准备的?

Overview

就一段废话,汉语复述于此:

文档是构建REST APIs的一个必要的部分。这篇文章当中,我们瞜一眼SpringDoc这个东东,这玩意儿是一个帮助Spring Boot (1.x和2.x都支持)应用简化创建和维护基于OpenAPI 3 Spec 的API文档的工具。

但其中也点明了一些东西:

  • OpenAPI 3 Spec,如果你的接口不是这个或者形式上差的远,那估计也会差点,具体OpenAPI 是啥,或者说具体怎么定义的,其实我也不知道,这个还需要后面延伸阅读
  • 这玩意儿面向的Spring Boot 应用,后文还会看到,即便是kotlin支持,也是为Spring 2.x application这类 Spring Boot提供支持的
  • 文章反正就是take a look,文学性点叫一瞥?所以也别期望面面俱到,就是个导读性质的,但是我看下来一遍之后觉的够现在用的了
  • 这个工具的优点是简化,也就是其实有标准的做法?我估计可以延伸阅读文章中的链接,take a look一下吧

Setting up springdoc-openapi

干货一节,没啥好翻的,照着copy到自己的pom文件、application.{properties,yaml}里面,以及浏览器地址栏里面就行了

我这里多记录一个,毕竟是自己的笔记么,如果SpringBoot配置了server.servlet.context-path,那么实际访问的地址(本地测试)还需要加上一段,例如我这里有一个工程,里面配了下面这么一段,当然其实不是我自己这么变态,是继承自原项目:

server.servlet.context-path=/publish

那么访问地址是

http://localhost:8080/publish/v3/api-docs/

对应yaml下载的就是

http://localhost:8080/publish/v3/api-docs.yaml

要不再给自己行个方便吧,pom里面加这段:

org.springdoc springdoc-openapi-ui 1.4.1

自定义路径配置那个,我觉得至少我不需要,反正就是springdoc.api-docs.path

Setting up springdoc-openapi With Swagger UI

这段确实挺奇怪的,为啥这么个行文,明明跟上面那个maven的dependency是一个东西,估计考虑很多人就是到网上copy一段东西,没打算看文章吧,当然了,人家也说了 All we have to do,秉承前文也许有这个意思?当我yy了吧,但是其实写代码有时候这也是一个点,适当的重复,在复用性上也许差一点(违反了DRY原则)比盲目的消除重复在表达力上更好

一堆配置,没啥好说的,路径啥的,没事儿别瞎改

有一个sort那个其实就是…这api文档结构本质上就是个列表么,那就可能得排个序么,哪个接口放前面哪个接口放后面啥的,所以有这么个配置

springdoc.swagger-ui.operationsSorter=method

然后举了个栗子,没啥太多可说其实,但,延伸两点吧:

  • 它也许颠覆了很多思维僵化同学的认知,controller直接调用了repository

    我有印象原来team里有个来自于百度的同学他就反复强调即便是没内容的service透传也是一种规范并引以为傲,但好在该同学基本功扎实所以水平摆在那里呢,毕竟没有把这种僵化三层当雷打不动的东西,否则他要是再看见Spring-Data-REST(后面还会遇到)估计得吐血了

  • 它这个段落演示了可以查看响应结果的结构,这里可能是个坑,提示了我们类型化响应的一个重要性和局限性——有时候不得不适应你用的工具和框架

Integrating springdoc-openapi With Spring WebFlux

为了适应Spring WebFlux(这个不展开了,主要是我也不懂,当作是Reactive版本的Spring MVC吧),终于有不一样的dependency了

剩下的没啥意思,也不翻了

Exposing Pagination Information

这一段英文本身其实没啥难理解的,首先又show了一个新的controller直接pia到repository脸上的例子,他说这些结合的好啊之类的我倒不怎么意外,我只是奇怪它展示的那个截图GET到底是怎么请求的(我简单写过一个Spring-Data-Rest的Project,就是租户路由那个,但是我好像没印象这么调用pageable来着…嗯,稍后把那个工程拉出来鞭尸),他也提到说:我们也许期望SpringDoc会在创建文档时候加入page、size、sort等参数…我明明都不知道我期望什么好么,所以我特别的加了一个类似的接口,嗯截图浪费下语雀流量吧

我试写的method是这样

image.png

然后我得到了这么一个文档

image.png
大概倒是知道这个GET接口是怎么呈现出来的了,但是这个描述确实太奇怪了,到底是sorted还是unsorted,到底是paged还是unpaged,这个可能就是文章中提到“不符期望”,还需要后面再加另一个dependency的原因吧

但是,我的测试配置除了他文章里提到的springdoc为spring-data-rest准备的适配器,我还加了个别的,否则启动不起来

org.springframework.boot spring-boot-starter-data-rest org.springdoc springdoc-openapi-data-rest 1.4.1

然后出来是这样的,跟他文档里的就差不多了
image.png

但是因为开启了spring-data-rest之后,如果不想直接暴露自己底层的repository——这就是spring-data-rest的目的,简单的CRUD几乎就不用再写了,那就需要做很多例外的配置,为了避免麻烦(我自己测试用的project毕竟是个正在用的线上的项目)我还是赶紧删了好

删了之后我正好再测试一个东西,之前没有springdoc的data-rest的时候,正好搞明白了如果GET的controller接口给一个Pageable这种有层次的对象(Pageable里有一个Sort),springmvc怎么给呈现出去,它实际上会用中括号把下一级属性表现出来(看sort里面的属性),但是提交到服务端时候会报错(这个我保留在工程里了,没有什么大碍感觉是),报错信息如下

Note: further occurrences of HTTP request parsing errors will be logged at DEBUG level.

java.lang.IllegalArgumentException: Invalid character found in the request target [/publish/wlot/catalogPage?offset=0&sort[sorted]=true&sort[unsorted]=true&sort[empty]=true&pageNumber=0&pageSize=0&paged=true&unpaged=true]. The valid characters are defined in RFC 7230 and RFC 3986

  1. at org.apache.coyote.http11.Http11InputBuffer.parseRequestLine(Http11InputBuffer.java:491)

细节不展开了,记录在这里,以备更细致的延伸阅读

Using springdoc-openapi Maven Plugin

这一节看怎么说了,从我目前的角度来看也是有点出戏,它主要是通过maven插件(还得配合spring boot 的maven插件)生成一个openapi的json或者yaml文档,这个,实际上就是前文提到过的

http://localhost:8080/publish/v3/api-docs.yaml

之所以要构建的时候生成,估计是一些企业级产品得交付物里面是需要这么一个东西的(之前某地公安项目他们就要求有swagger的api doc,有没这个独立的json或者yaml的doc,这个回头问问涛哥),这个可以和他介绍的outputDir这个配置参数对上,但是他也有apiDocsUrl,不知道干嘛用的,岂不是和前面spring boot application.properties文件里的东西重了

其他的也是很简单的E文(但是他要是读给我听我真未必听得懂…)可能一个潜在的要点就是记得这个maven插件缺省的工作阶段是 integration-test,这个意味着我们通常用到的maven clean package … 实际上产出不了这个东西

总之,这一段很多细节我也不是很感兴趣,我也没试

Automatic Document Generation Using JSR-303 Bean Validation

这段儿也很简单,讲的是直接识别JSR 303 Bean Validation注解,并且形成一个独立的Schema描述,这个描述在整个文档的底部

我在想这周这文档是不是太浅了选的…

Generate Documentation Using @ControllerAdvice and @ResponseStatus

这块儿讲的也简单(确实特么的太简单了这点儿E文,我仔细分析一下句式要不),就是这些一般用来统一控制异常处理截面的注解直接就能对应到接口上,但前提是…异常链路的明确指明,这块儿说多了变成观点了

我也没试,这块儿挺明白的

Generate Documentation Using @Operation and @ApiResponses

这块儿是重头,翻一下吧,说好了是读英文么

接下来,让我们瞜瞜应该如何通过使用OpenAPI-Spec的注解来为我们的API来添加描述,为了搞这个事情,我们用@Operation 和@ApiResponses注解来标注一下我们controller里面的/api/book/{id} 这个endpoint

中间balabala的展示就略去了

如上所示,那些我们通过@Operation添加的文字放在了API操作级别(译注,他这个也许老外能明白,或者swagger这个文档结构真有这个名字吧,我一开始是没明白,对照了图才知道说的就是GET /xxx 那行)。类似的,各类在@ApiResponses容器内@ApiResponse元素中的描述信息,也呈现在这里为我们的API响应添加了描述信息

很明显的(也应该注意到),我们没有从400和404这些响应上看到任何的结构的信息,因为我们给这些响应只设置了一个空的@Content注解,所以他们就只显示描述信息了
_

Kotlin Support

自打Spring Boot 2.x 对Kotlin有了first-class 的支持,SpringDoc 也就支持这个JVM语言在Boot 2.x 应用中的开箱即用能力

在这一章,我们会用Kotlin创建一个简单的Foo API

在初始化安装(译注:spring boot 的kotlin 支持的初始化,而且指的是另一篇教程的某个章节的操作)之后,我们添加一个数据类和一个Controller。我们在一个sub-package中为我们的Boot App添加他们(指的前面那俩类),以便于这个新加的FooController和早一点的那个BookController可以共存
_
后面就是零星两句了就不翻了,但是我得承认我在把例子都跑完一遍之后我不太确定他说的,要单独再为kotlin加一个注解就能为Foo 这个kotlin类型加上类似JSR-303时候的效果到底是啥意思

Conclusion

总算给了一段文字让我看一下

在这篇文章中,我们学习了如何为我们的工程设置springdoc-openapi。接着我们看到了springdoc-openapi是怎么继承SwaggerUI的(译注:其实就是自己吹一下,我竟然还琢磨了一会儿它这话到底啥意思),我们也看到了如何在Spring Webflux工程中做到这一点

接下来,我们使用 springdoc-openapi 的maven插件生成了我们API的OpenAPI定义,然后我们看到了从Spring Data中,如何暴露分页和排序信息。那之后,我们又看到了 springdoc-openapi 如何自动的根据JSR 303 Bean Validation annotations ,@ControllerAdvice中的@ResponseStatus创建更丰富的文档材料

接着我们学习了如何使用一组OpenAPI-specific的注解来为我们的API添加描述。最终我们小窥了一下对Kotlin的OpenAPI支持

Springdoc-openapi 根据OpenAPI 3 spec来创建API 文档。此外,他也帮我们配置Swagger UI,并让API 文档的生成成为了一件相当轻松的任务

如以往一样,这些代码可以通过GitHub来访问到

总结得这么得体,我就不多说什么了,后面再有些细节自己动个手吧

T

其实重启打开Intellij并不是一个常规操作,刚好有一次,那直接学了吧

image.png

这个可能不是太实用,一般来说最近打开的在重新打开时候会是打开着的吧,也有可能是给那些打开好多好多文件的人准备的,猛一下找不到,用这个显示出来,注意还有一个option,这个changed only,不知道是不是git相关

这个tip的截图其实有个bug,发现了吗?那就是截图是OSX的,但是tip明显是windows的,不知道后面的版本(我现在是2020.1 Ultimate)会不会有改进,再次遇上这个tip,不知道是何年何月了

second tip

上面那个是上周得,说起来不太令人满意,不是啥有用的东西赶脚

这里记录一个kubectl得命令细节吧,是 kubectl rollout status,他这个如果deployment正在执行滚动更新,就会一直阻塞着一直到预先设定的超时时间,这个时间rancher里可以设置,如下图,就是滚动更新那个UI panel里面的,这个参数相关文档可参照

image.png
缺省不设得话,会给一个600s

image.png
实际上就是这个

这个东西可以自动化发布时候通过它退出时得exitcode,给是否自动回退一个指示,回退用kubectl rollout undo,但是这个undo也有可能有问题,所以不要奢望这个undo一定能成功,这个job也是rollout失败,所以job总之是要标记为fail

S

捋之前运维小朋友留下的一堆遗产,我本来以为特定问题上,我够抠细节了,这次仔细review才发现还是有好多的小坑,也不乏是我给挖的,这里记录一下,并且重申自己这个观点,干啥都得注意不能不求甚解

jenkins

先说view吧,这是作业

如果没有足够的理由,不支持master非得跑在容器里面,但是这事儿其实也不绝对,毕竟容器,甚至通过容器编排引擎,自然也有它的好处,细节展开,自己能想到的正反两方面:

  • 目前看起来,还是不要,至少首选是没必要的
    • 首先源于jenkins这东西就不是容器时代的东西…
    • 其次扯点具体的,强行得放在容器里,原先很多的配置管理的东西反倒搞得很麻烦——本来在启动jenkins得当前用户目录里面(前提还是linux,windows估计也差不多)一个隐藏目录就有全部配置了,容器得还得挂卷,k8s另当别论,就是认定该飘来飘去的服务实体和服务持久化状态关系的问题,但是多了一层抽象,这虽然不能直接算问题,但是看后面,其实是对一些基础组件能力后续添加带来了极大的限制
    • 再次得再吐槽一个,其实这个可能不能算是jenkins得,maven构建这玩意儿吧,缓存在.m2/repository里面多自然的方法,但是容器一重起就没了,要么挂卷,要么挂卷容器,总之好烦,k8s里面也是一样
    • 最后再吐一个,jenkins就是个job manager,但是实际执行需要很多外部的工具链来支撑,比如git,maven,java,这些东西按说原来就是运行job得环境配置就完了,但是现在这个jenkins容器里一跑…现在也是挂卷,也是重启的问题,挂卷如果有变更吧,比如重新加个工具比如npm,怎么也得重启一下,重启容器其实也不是什么大不了的事情,但本来,其实是不用重启的
  • 那是不是一定不能容器里跑呢,也未必
    • 可以把改挂得所有的基础目录直接挂好了就省心了,以后加东西也就都是往这里面加
    • 可以充分利用slave节点,甚至master就不管具体的job构建执行这些事,这时候就跟跑不跑docker里面,逻辑上就没啥强关联关系了(这个只是逻辑上推测,还没详细得试过)
    • 从上面这个角度来讲,更流行的但是我一直不太理解的在容器内执行构建任务(其实明白,只是觉的它太过不普世,因为job环境用docker甚至k8s来跑,意味着已经有相当多的资源可以用于CI/CD了,它们那个阶段是资源利用率提升的问题,但绝大多数组织级得问题其实是投入这方面的资源还相当相当相当…的优先)也是一种解决把master跑在容器里时候,工具链环境准备的一种自然的补偿(image里面已经好了,只需要按需run起来就好了)

      容器进程的用户问题

这个也先说view(两个viewpoint了,这岂不是提前超额完成作业),适当的还是得控制一下执行容器得用户,但是一定得知道自己在做什么,并且还要明白哪些方面自己什么没有做,展开一下:

  • docker在区分特权模式之后(没具体考证版本0.6?),容器内的root和容器外的root不完全是一个东西了,这一点要感谢新来的小馨同学得提醒,详情见docker相关文档及链接
  • 但是实际上总的来说因为容器和其host实际上共享一套内核,所以UID还是一个,也就是说这个root其实还是外面那个root,只不过限制了一些能力
  • 所以如果有必要,还是应当限制一下,可以避免的问题,至少有不当的目录挂载,减少了不当得文件获取和编辑,就能又封住一大片的潜在的灰色地带
  • 具体限制的手法可以参照,这个主要是自己烧制得image,有时候还有外部第三方得image,除了安全合规扫描之外,还有一些套路配置方法可以考虑,避免image无良,特别是我们使用k8s时,可参照k8s得pod安全策略文档

Java/Spring Boot启动时候那个套路参数

这个套路参数是,-Djava.security.egd=file:/dev/./urandom

老实说加这玩意儿当然也是我让加的,但是我确实这次又注意到她的时候,忘了他是干嘛的了…

但是我有印象从哪儿抄的,因为时过境迁了,所以我还特地考证了一下大概其时间得旧版本,因为注意到它新版本文档里没提到这个玩意儿了…

仔细看了下它原来版本的文档,也确实回忆起来了说是为加速tomcat启动的,但是旧文档也提到了,相对新的spring boot(也没提具体版本)也不需要这玩意儿了

但是单独得搜一下,或者说更根源的因素可以参考这个,我多事得看了下现在我IDE里面有的源码(java 12得),不一样了,调用的是有参得构造函数,但是进去之后,也够让人无奈的,截图如下吧,浪费我的语雀流量简直是

image.png
image.png

这玩意儿,我也不知道该说什么了

总之最后,也得有个view吧,结合比较新版本得spring boot docker文档里面提到的所谓更深入的讨论这个主题的那个文档,我觉得,这就是一个相对简单的事情了:

这个参数既然目的性这么明确,不用非打到docker image里面,而是在运维环境得环境变量中设置JAVA_OPTS里面按需加上比较好,至于trick用得那个dot, 无伤大雅,也不知道它到底哪个版本去改好了这个bug(?真的是bug么,其实我没仔细读源码),与其花时间去记录和分辨到底哪个版本它真把bug解了,那索性还是这么写来得简单,特别是我现在考虑放开每个服务所使用的JDK版本(最低是8这个算是底线了吧)