内容简介:本文翻译自:我很高兴的宣布Quarkus 是一个将 Java 代码编译为本机代码(使用GraalVM)并删除运行时不需要的代码的框架。
本文翻译自: http://belaban.blogspot.com/2019/07/compiling-jgroups-to-native-code-with.html
我很高兴的宣布 Quarkus 官方发布 JGroups 的扩展!
What?
Quarkus 是一个将 Java 代码编译为本机代码(使用GraalVM)并删除运行时不需要的代码的框架。
Quarkus 在构建阶段分析代码,并删除在运行时未使用的代码,以便拥有一个可以快速启动的小型可执行文件。不过这意味着无法在运行时使用反射,因为在构建时删除了所有未使用的类。 但是,可以在构建时使用反射。
影响 JGroups 的其他限制是线程和套接字的创建。 两者都无法在构建时完成,但必须在运行时完成。
那么为Quarkus提供JGroups扩展的重点是什么呢?
虽然JGroups应用程序可以直接编译为本机代码(使用GraalVM的本机映像),但它很麻烦,并且必须重新构建应用程序以适应本机编译的限制。
相反,JGroups 扩展提供了一个可以注入应用程序的JChannel。 已根据配置文件创建通道,并通过扩展连接(=加入群集)。 扩展负责在正确的时间(构建或运行时)执行反射,套接字创建和线程启动,用户无需担心这一点。
How?
接下来让我们看一个具体的例子。
POM 引入扩展 groupId=org.jgroups.quarkus.extension 和 artifactId=quarkus-jgroups. 这样就可以提供一个可注入的 JChannel。
主类是 ChatResource,代码如下:
@ApplicationScoped
@Path("/chat") public class ChatResource extends ReceiverAdapter implements Publisher<String> { protected final Set<Subscriber<? super String>> subscribers=new HashSet<>(); @Inject JChannel channel; protected void init(@Observes StartupEvent evt) throws Exception { channel.setReceiver(this); System.out.printf("-- view: %s\n", channel.getView()); } protected void destroy(@Observes ShutdownEvent evt) { Util.close(channel); subscribers.forEach(Subscriber::onComplete); subscribers.clear(); } @GET
@Produces(MediaType.TEXT_PLAIN) @Path("/send/{msg}") public String sendMessage(@PathParam("msg") String msg) throws Exception { channel.send(null, Objects.requireNonNull(msg).getBytes()); return String.format("message \"%s\" was sent on channel \n", msg); } @GET
@Produces(MediaType.SERVER_SENT_EVENTS) @Path("/subscribe") public Publisher<String> greeting() { return this; } public void receive(Message msg) { onNext(msg); } public void receive(MessageBatch batch) { for(Message msg: batch) onNext(msg); } public void viewAccepted(View view) { System.out.printf("-- new view: %s\n", view); } public void subscribe(Subscriber<? super String> s) { if(s != null) subscribers.add(s); } protected void onNext(Message msg) { String s=new String(msg.getRawBuffer(), msg.getOffset(), msg.getLength()); System.out.printf("-- from %s: %s\n", msg.src(), s); subscribers.forEach(sub -> sub.onNext(s)); } }
它有一个由Arc注入的JChannel通道(Quarkus中使用的依赖机制)。 该通道在注入时已经完全创建并连接。
receive(Message) 和 receive(MessageBatch) 方法接收由其自身或集群中的其他成员发送的消息。 它反过来通过Publisher接口发布它们。 因此,所有订户都将收到群集中发送的所有消息。
当收到格式为http://localhost:8080/chat/send/mymessage 的 URL 时,将调用 sendMessage() 方法。 它接受字符串参数(“mymessage”)并使用注入的通道将其发送给集群的所有成员。
URL http://localhost:8080/chat/subscribe (或者在浏览器中的 http://localhost:8080/streaming.html) 可用来订阅消息。
演示
接下来我们运行两个实例的集群,打开两个命令行窗口,并输入如下的命令:
Shell1: [belasmac] /Users/bela/quarkus-jgroups-chat$ mvn compile quarkus:dev ... [INFO] --- quarkus-maven-plugin:0.18.0:dev (default-cli) @ quarkus-jgroups-chat --- 2019-07-03 14:12:05,025 DEBUG [org.jgr.qua.ext.JChannelTemplate] (main) creating channel based on config config=chat-tcp.xml, bind_addr=, initial_hosts=, cluster=quarkus-jgroups-chat ------------------------------------------------------------------- GMS: address=belasmac-19612, cluster=quarkus-jgroups-chat, physical address=127.0.0.1:7800 ------------------------------------------------------------------- -- view: [belasmac-19612|0] (1) [belasmac-19612] Shell2: [belasmac] /Users/bela/quarkus-jgroups-chat$ mvn compile quarkus:dev -Dquarkus.http.port=8081 ... [INFO] --- quarkus-maven-plugin:0.18.0:dev (default-cli) @ quarkus-jgroups-chat --- 2019-07-03 14:15:02,463 DEBUG [org.jgr.qua.ext.JChannelTemplate] (main) creating channel based on config config=chat-tcp.xml, bind_addr=, initial_hosts=, cluster=quarkus-jgroups-chat ------------------------------------------------------------------- GMS: address=belasmac-25898, cluster=quarkus-jgroups-chat, physical address=127.0.0.1:7801 ------------------------------------------------------------------- -- view: [belasmac-19612|1] (2) [belasmac-19612, belasmac-25898]
这里我们需要一个系统属性设置 quarkus.http.port=8081 ,否则会产生端口冲突,因为默认的 8080 端口已经被第一个应用占用。
输出信息显示集群共有两个成员。
我们可以通过调用 curl http://localhost:8080/chat/send/hello%20world 和 curl http://localhost:8081/chat/send/message2 来发送消息。
两个命令行窗口都显示接收到同样的消息:
-- view: [belasmac-19612|1] (2) [belasmac-19612, belasmac-25898] -- from belasmac-19612: hello world -- from belasmac-25898: message2
当然我们也可以使用浏览器来发送 HTTP GET 请求。
当在浏览器中订阅消息时 (http://localhost:8081/streaming.html),会有如下效果:
注意这些频道都是绑定到本机 loopback (127.0.0.1) 地址上。可以通过 application.properties 配置中的 bind_addr 和 initial_hosts 来进行修改。
quarkus.channel.config=chat-tcp.xml quarkus.channel.cluster=quarkus-jgroups-chat # quarkus.channel.bind_addr=192.168.1.105 # quarkus.channel.initial_hosts=192.168.1.105[7800]
另外我们也可以通过系统属性来进行设置,例如:
[belasmac] /Users/bela/quarkus-jgroups-chat$ mvn compile quarkus:dev -Dbind_addr=192.168.1.105 -Dinitial_hosts=192.168.1.105[7800],192.168.1.105[7801] ... [INFO] --- quarkus-maven-plugin:0.18.0:dev (default-cli) @ quarkus-jgroups-chat --- 2019-07-03 14:38:28,258 DEBUG [org.jgr.qua.ext.JChannelTemplate] (main) creating channel based on config config=chat-tcp.xml, bind_addr=, initial_hosts=, cluster=quarkus-jgroups-chat ------------------------------------------------------------------- GMS: address=belasmac-10738, cluster=quarkus-jgroups-chat, physical address=192.168.1.105:7800 ------------------------------------------------------------------- -- view: [belasmac-10738|0] (1) [belasmac-10738]
编译本机可执行程序
要将应用编译成可执行程序,可以使用 mvn package -Pnative 命令:
[belasmac] /Users/bela/quarkus-jgroups-chat$ mvn package -Pnative [INFO] Building jar: /Users/bela/quarkus-jgroups-chat/target/quarkus-jgroups-chat-1.0.0-SNAPSHOT.jar [INFO] [INFO] --- quarkus-maven-plugin:0.18.0:build (default) @ quarkus-jgroups-chat --- [INFO] [io.quarkus.deployment.QuarkusAugmentor] Beginning quarkus augmentation [INFO] [org.jboss.threads] JBoss Threads version 3.0.0.Beta4 [INFO] [io.quarkus.deployment.QuarkusAugmentor] Quarkus augmentation completed in 1343ms [INFO] [io.quarkus.creator.phase.runnerjar.RunnerJarPhase] Building jar: /Users/bela/quarkus-jgroups-chat/target/quarkus-jgroups-chat-1.0.0-SNAPSHOT-runner.jar [INFO] [INFO] --- quarkus-maven-plugin:0.18.0:native-image (default) @ quarkus-jgroups-chat --- [INFO] [io.quarkus.creator.phase.nativeimage.NativeImagePhase] Running Quarkus native-image plugin on OpenJDK 64-Bit Server VM [INFO] [io.quarkus.creator.phase.nativeimage.NativeImagePhase] /Users/bela/graalvm/Contents/Home/bin/native-image -J-Djava.util.logging.manager=org.jboss.logmanager.LogManager --initialize-at-build-time= -H:InitialCollectionPolicy=com.oracle.svm.core.genscavenge.CollectionPolicy$BySpaceAndTime -jar quarkus-jgroups-chat-1.0.0-SNAPSHOT-runner.jar -J-Djava.util.concurrent.ForkJoinPool.common.parallelism=1 -H:FallbackThreshold=0 -H:+ReportUnsupportedElementsAtRuntime -H:+ReportExceptionStackTraces -H:+PrintAnalysisCallTree -H:-AddAllCharsets -H:EnableURLProtocols=http -H:-SpawnIsolates -H:+JNI --no-server -H:-UseServiceLoaderFeature -H:+StackTrace [quarkus-jgroups-chat-1.0.0-SNAPSHOT-runner:93574] classlist: 6,857.25 ms [quarkus-jgroups-chat-1.0.0-SNAPSHOT-runner:93574] (cap): 4,290.72 ms [quarkus-jgroups-chat-1.0.0-SNAPSHOT-runner:93574] setup: 6,430.30 ms 14:43:05,540 INFO [org.jbo.threads] JBoss Threads version 3.0.0.Beta4 14:43:06,468 INFO [org.xnio] XNIO version 3.7.2.Final 14:43:06,528 INFO [org.xni.nio] XNIO NIO Implementation Version 3.7.2.Final [quarkus-jgroups-chat-1.0.0-SNAPSHOT-runner:93574] (typeflow): 17,331.26 ms [quarkus-jgroups-chat-1.0.0-SNAPSHOT-runner:93574] (objects): 24,511.12 ms [quarkus-jgroups-chat-1.0.0-SNAPSHOT-runner:93574] (features): 1,194.16 ms [quarkus-jgroups-chat-1.0.0-SNAPSHOT-runner:93574] analysis: 44,204.65 ms [quarkus-jgroups-chat-1.0.0-SNAPSHOT-runner:93574] (clinit): 579.00 ms [quarkus-jgroups-chat-1.0.0-SNAPSHOT-runner:93574] universe: 1,715.40 ms [quarkus-jgroups-chat-1.0.0-SNAPSHOT-runner:93574] (parse): 3,315.80 ms [quarkus-jgroups-chat-1.0.0-SNAPSHOT-runner:93574] (inline): 4,563.11 ms [quarkus-jgroups-chat-1.0.0-SNAPSHOT-runner:93574] (compile): 24,906.58 ms [quarkus-jgroups-chat-1.0.0-SNAPSHOT-runner:93574] compile: 34,907.28 ms [quarkus-jgroups-chat-1.0.0-SNAPSHOT-runner:93574] image: 4,557.78 ms [quarkus-jgroups-chat-1.0.0-SNAPSHOT-runner:93574] write: 2,531.16 ms [quarkus-jgroups-chat-1.0.0-SNAPSHOT-runner:93574] [total]: 109,858.54 ms [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 01:58 min [INFO] Finished at: 2019-07-03T14:44:40+02:00
这使用的是 GraalVM 的本地应用映像来生成一个本地可执行程序。生成完成后将在 ./target 目录产生一个可执行文件:
其大小约为 27MB ,在 MacOS 的可执行程序如下:
[belasmac] /Users/bela/quarkus-jgroups-chat/target$ ls -lh quarkus-jgroups-chat-1.0.0-SNAPSHOT-runner -rwxr-xr-x 1 bela staff 27M Jul 3 14:44 quarkus-jgroups-chat-1.0.0-SNAPSHOT-runner [belasmac] /Users/bela/quarkus-jgroups-chat/target$ file quarkus-jgroups-chat-1.0.0-SNAPSHOT-runner quarkus-jgroups-chat-1.0.0-SNAPSHOT-runner: Mach-O 64-bit executable x86_64
接下来可以运行这个程序:
[belasmac] /Users/bela/quarkus-jgroups-chat/target$ ./quarkus-jgroups-chat-1.0.0-SNAPSHOT-runner ------------------------------------------------------------------- GMS: address=belasmac-55106, cluster=quarkus-jgroups-chat, physical address=127.0.0.1:7800 ------------------------------------------------------------------- -- view: [belasmac-55106|0] (1) [belasmac-55106]
当您自己运行时,您会注意到第二个及后续成员的快速启动时间。 为什么不是第一个成员? 第一个成员必须等待GMS.join_timeout millis(在chat-tcp.xml中定义)以查看它是否发现任何其他成员,因此它总是会遇到此超时。
要改动 bind_addr 和 initial_hosts 的话,application.properties 必须在编译成本机代码之前进行修改。
注意事项
quarkus-jgroups扩展依赖于JGroups-4.1.2-SNAPSHOT,除非已将快照存储库添加到POM(或settings.xml),否则它可能无法找到。 或者通过如下命令在您的本地maven仓库中生成并安装此工件:
git clone https://github.com/belaban/JGroups.git; cd JGroups; mvn install
当前的版本只支持 TCP 通讯,UDP 需要在 GraalVM 支持 MulticastSockets 后才可以使用。
出于某些不明原因,必须在 POM 中启用 enableJni ,否则编译成本机代码时会失败。
<enableJni>true</enableJni>
希望我能快速理解这个原因并解决问题。
总结
这是快速将 JGroups 移植到本机代码的方法。 有关反馈和问题,请使用JGroups邮件列表。
接下来的计划:
- 通过扩展提供更多 JGroups 类的支持,例如 RpcDispatcher (用以执行远程方法调用)
- 提供本地可执行程序的 Docker 映像
- 支持 UDP
- 降低可执行文件的体积
Enjoy!
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- golang编译和docker执行
- 玩转php的编译与执行
- 说说如何使用 Geany 编译与执行 Python
- GO笔记之详解GO的编译执行流程
- Go语言:编译其他系统的可执行程序
- 编译原理实战入门:用 JavaScript 写一个简单的四则运算编译器(三)模拟执行
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Beginning XML with DOM and Ajax
Sas Jacobs / Apress / 2006-06-05 / USD 39.99
Don't waste time on 1,000-page tomes full of syntax; this book is all you need to get ahead in XML development. Renowned web developer Sas Jacobs presents an essential guide to XML. Beginning XML with......一起来看看 《Beginning XML with DOM and Ajax》 这本书的介绍吧!