- vert.x是一个基于JVM、轻量级、高性能的应用平台,基于Netty全异步通信,并扩展出了很多有用的特性。重点:全异步通信,几乎所有IO相关的操作都处理成了异步通信,性能很好。vert.x的黄金法则就是不要阻塞(Don’t block me!)。
- 支持多种编程语言,不过绝大多数使用者都是java系的。
- 性能在techempower评测中处于前列,查看地址 ,在最新一期评测中vert.x的综合性能处于java框架第3位
- 官网地址
- 一句话介绍版:它是一门开发语言,它写的代码可以编译成jar文件运行在jvm上,可以与java互相调用;它有类似goroutine的coroutine协程;它还有很多提高开发效率的语法糖。
- 搞笑介绍版:
美人鱼名场面改写(本人原创) 技术大佬A:尹先生,你好你好。有什么我们可以帮到您的吗? 我:我接下来要说的,你们千万别害怕。 技术大佬A:我们是技术大佬,我们什么没见过?你请说。 我:我,喜欢上了Kotlin 技术大佬A:Kotiln是哪个妹子? 我:不是妹子,是一门特别简单特别容易上手而且特别好用的编程语言! 技术大佬B:画了一杯咖啡 我:呃,不,比这个写起来简单 技术大佬B:画了两条蛇 我:这个又执行效率太低了。 技术大佬B:画了个红宝石 我:它有一个牛逼的爹 技术大佬A伸手接过画纸:画了一只雨燕鸟 我弹掉纸:Kotiln啊!超好用语法糖用过没,就是那个亲爹是Jetbrains干爹是Google的Kotiln啊,明白吗? 技术大佬A:明白了,你继续说。 我:它说我以前用的编程语言很弱,它有data class,open class,object class,lambda表达式,这些都超好用的啊。 技术大佬A,B:(后仰) 我:我看了一下技术文档,就疯狂喜欢上它了。简直太好用了,还支持spring全家桶和vert.x框架…… 技术大佬B:(笑) 我:你笑什么? 技术大佬B:我想起高兴的事情。 我:什么高兴的事情? 技术大佬B:我儿子会写“Hello World”了。(技术大佬A笑) 我:你又笑什么? 技术大佬A:我儿子也会写“Hello World”了。 我:你们儿子,是同一个人? 技术大佬A、B:对对,(笑),不是,是在同一个兴趣班。 我:我再重申一遍,我没开玩笑。(AB笑) 技术大佬A:我们言归正传,您说的Kotiln,开发中好用吗? 我:他不是好用不好用的问题,它真的是那种很少见的…它很灵活,也很优雅。遗憾的是,时间太急了,没来得及用在生产上…… 技术大佬了:(笑) 我:你欺人太甚,我忍你很久了! 技术大佬B:我儿子会写“Hello World”了。 我:你明明在笑我都没停过。 技术大佬B:尹先生,我们是受过专业训练的,无论多菜的人,我们都不会笑,除非忍不住。 技术大佬A:不如这样,尹先生,你先回去,我们研究一个最简单的Demo,等会来给你演示。 我:好,你们快点,认真一点,最好就用springboot!(出门) 技术大佬A,B:(大笑) 我:(探头) 技术大佬B:尹先生,你有什么要补充吗? 我:(离开) 技术大佬A、B:继续笑。 我:(探头) 技术大佬A:尹先生? 我:(无奈离开)
- 官网地址
- GraalVM是一个高性能的通用虚拟机,可以运行使用Jvm系语言、JavaScript、Python 3、Ruby、R等语言开发的应用。
- 性能高,如果是运行在GraalVM上,可以获得比OPENJDK上更高的性能,可参考官方比较,并且GraalVM也是Oracle家的,算是OPENJDK的亲兄弟了。
- 本文的重点来了,GraalVM甚至可以将Jvm系语言打包成二进制原生应用。提高应用性能,尤其是提高了启动速度,特别适合云原生应用、FaaS等场景。
- 原生应用打包的局限性:为了减小打包应用的体积,GraalVM并不会把所有的class全部打入应用中,而是抽取需要的部分加入。但是, java的反射以及代理是通过class文件分析不出来具体使用了哪些类哪些方法的。所以对于这样的情况,我们需要做一些配置文件,让GraalVM知道哪些类可能会被反射代理等用到, 将其加入到应用中,同理还有一些类有static代码块,是在打包期(也就是build期)就需要计算出来的,所以也要加入相关配置告诉GraalVM
- 官网地址
- 一个简单的vert.x的web服务
- vert.x的mysql数据库操作包vertx-mysql-client
- vert.x的redis操作包vertx-redis-client
- Kotlin支持包:vertx-lang-kotlin和vertx-lang-kotlin-coroutines
- 日志输出工具:自带的java.util.Logging
- vert.x版本为4.2.1
- 开始我先尝试用Java而非Kotlin来写代码,也只用到了mysql和redis,暂时没有使用日志。(重点!后面会有用到Kotlin和日志的坑的)
- vert.x官网有一篇文章指导如何打包成原生应用,参考地址 ,原理上大概是这样,但是实际操作过程中发现按这样打不出来。 不停地报一堆类"should be initialized at run time got initialized during image building"
- 天无绝人之路,在github上找到这篇文章对应的源码 。然后、但是,克隆下来之后发现仍然是一样的问题。 看来不是自己操作的问题,应该是这篇howto太老了?
- vert.x的官方文档有问题,那就从GraalVM开始,来了解如何打包原生应用吧,学会了就不只是局限于vert.x打包了,而是放之四海而皆准。 先了解了一下打包要用的相关配置文件,以及其作用,参考文档 。
- 看完之后,发现觉得是vert.x官方文档过度优化了,配置了一堆initialize-at-build-time的类,加上一堆initialize-at-run-time的类,这些配置就是之前出现的错误 "should be initialized at run time got initialized during image building"的原因。
- 直接把howto上的配置文件native-image.properties文件中的initialize-at-build-time和initialize-at-run-time的的类全部删完,然后再尝试打包,报错, 把提示错误的类加入配置,再打包,再报错,再加。。。最后加了3个类到initialize-at-run-time的配置下面就OK了
- 注意:要把自己通过反射启动的Verticle加入reflect-config.json中。
- IDEA有个功能,直接右键点一个类,然后选择【Convert Java file to Kotlin file】即可,转换后的程序居然可以直接用,真是大赞
- 然而我高兴得太早了,vert.x全是Future式的异步写法,很是反人类,我寻思既然用了Kotlin了,为什么不用coroutine来换成同步写法呢,正好vert.x提供了完整 支持Kotlin的coroutine的API,真是太赞了
- 写完,打包成原生应用,打包成功,然而一执行,NoClassDef...coroutine的启动居然用到了kotlin.random.Random类,匪夷所思,把这个类添加进 GraalVM打包的配置文件reflect-config.json中,然后又有新的Kotlin类找不到,继续加吧。还好目前就遇到两个,以后使用了更多Kotlin的原生类的时候可能会加更多, 谁知道呢。总算搞定了。
- vert.x默认是用的logback+SLF4J输出日志,这在以jar包形式运行的时候没有任何问题,很完美。但是加入之后尝试打包成原生应用就不停报错了, 当然报错也还是我们的老熟人,哦不,老熟错:一堆类"should be initialized at run time got initialized during image building"
- 当然我心想日志输出嘛,能有多少依赖,我一个一个类加到配置里面呗,没想到按下左边,右边又出错,如此循环往复,配置越加越多,也有越来越多的类发生了我们的老熟错。
- 我放弃了,但是GraalVM的官网又给了我希望。不知道是不是GraalVM的开发者也试过用各种日志组件出错,总之它的官方文档里面专门有 一篇 来介绍怎么在原生主应用中输出日志的。是的,它推荐使用java.util.Logging, java自带的日志输出工具,仿佛让我又回到了梦开始的地方
- 按官方文档的说法,Logger的初始化既可以Build-Time,也可以在Runtime,我选择了在Build-Time,找了个地方写了一段static代码来初始化java.util.Logging。
object Starter { @JvmStatic fun main(args: Array<String>) { Launcher.main(args) } init { try { LogManager.getLogManager().readConfiguration(Starter::class.java.getResourceAsStream("/logging.properties")) val logger = Logger.getLogger(Starter::class.java.name) logger.info("logger init completed") } catch (e: IOException) { e.printStackTrace() exitProcess(0) } } }
- 注意:
- 用到的配置文件logging.properties,要添加到GraalVM打包的配置文件resource-config.json中方可使用
- 根据GraalVM的官方文档中提到的,要把java.util.logging.FileHandler类添加到配置文件reflect-config.json中。
- 我没有使用vert.x自身的Launcher类来运行main函数,而是重写了一个Starter类来调用它,主要目的是保证static代码段最早执行,其实似乎是没有必要的。
-
组件版本:
组件名 版本 GraalVM 20.3.0 vert.x 4.2.1 Kotlin 1.5.10 -
打包成fat-jar:mvn clean package
-
打包成原生应用:mvn clean package -f pom-native.xml
-
注意,打包成原生应用windows可能不行,因为除了GraalVM之外,还需要额外安装C++编译器,GraalVM官方说安装VS 2017 C++ builder即可,但是我试过不行, 幸好我还有一台Macbook
-
执行fat-jar:java -jar ./target/vertx-native-try-1.0.0-SNAPSHOT-fat.jar run cn.yjl.vertx.MainVerticle -conf ./conf/application.json
-
执行原生应用:./target/vertx-native-try run cn.yjl.vertx.MainVerticle -conf ./conf/application.json