graalvm 编译原生java 解决反射的问题 maven配置


由来

之前已经采坑完成了基于maven项目的java 二进制编译,但实际上基于原生的程序,在运行时是无法进行反射的,需要单独生成配置文件

手动配置是不可能的,所以graavm提供一个agent工具,该工具会生成整个代码中需要用到反射的配置文件,但前提是,需要你把项目打成jar包....生成配置文件之后,再编译成二进制。
好了,编译不成功遇到问题可以来群里找我 626070845,接下来,开干

实战

pom

<?xml version="1.0" encoding="UTF-8"?>


    com.langs
    1.0-SNAPSHOT
    4.0.0

    

        17
        17

    
    native-netty-log4j

    
        
            cn.hutool
            hutool-all
            5.8.0.M3
        

        
            io.netty
            netty-all
            4.1.75.Final
        

        
            org.slf4j
            slf4j-api
            1.7.5
        

        
            org.slf4j
            slf4j-log4j12
            1.7.5
        
        
            log4j
            log4j
            1.2.12
        


        
            com.ibeetl
            beetl
            3.10.0.RELEASE
        



    


    
        native-image-js
        

































            
                org.graalvm.nativeimage
                native-image-maven-plugin
                20.3.0



                


                    
                    ${project.artifactId}
                    
                    com.lang.Application
                    



                    
                        --no-fallback

                        --initialize-at-build-time=org.apache.log4j.PatternLayout
                        --initialize-at-build-time=org.apache.log4j.Layout

                        --initialize-at-build-time=org.slf4j.MDC
                        --initialize-at-build-time=org.slf4j.LoggerFactory
                        --initialize-at-build-time=org.slf4j.impl.StaticLoggerBinder
                        --initialize-at-build-time=org.apache.log4j.helpers.Loader
                        --initialize-at-build-time=org.apache.log4j.Logger
                        --initialize-at-build-time=org.apache.log4j.helpers.LogLog
                        --initialize-at-build-time=org.apache.log4j.LogManager
                        --initialize-at-build-time=org.apache.log4j.spi.LoggingEvent
                        --initialize-at-build-time=org.slf4j.impl.Log4jLoggerFactory
                        --initialize-at-build-time=org.slf4j.impl.Log4jLoggerAdapter
                        --initialize-at-build-time=com.lang.server.handler.FarChannelHandler
                        --initialize-at-build-time=java.beans.Introspector
                        --initialize-at-build-time=com.sun.beans.introspect.ClassInfo

                        --initialize-at-run-time=io.netty.channel.epoll.Epoll
                        --initialize-at-run-time=io.netty.channel.epoll.Native
                        --initialize-at-run-time=io.netty.channel.epoll.EpollEventLoop
                        --initialize-at-run-time=io.netty.channel.epoll.EpollEventArray
                        --initialize-at-run-time=io.netty.channel.DefaultFileRegion
                        --initialize-at-run-time=io.netty.channel.kqueue.KQueueEventArray
                        --initialize-at-run-time=io.netty.channel.kqueue.KQueveEventLoop
                        --initialize-at-run-time=io.netty.channel.kqueue.Native
                        --initialize-at-run-time=io.netty.channel.unix.Errors
                        --initialize-at-run-time=io.netty.channel.unix.1ovArray
                        --initialize-at-run-time=io.netty.channel.unix.Limits
                        --initialize-at-run-time=io.netty.util.internal.logging.Log4JLogger
                        --initialize-at-run-time=io.netty.channel.unix.Socket
                        --initialize-at-run-time=io.netty.channel.ChannelHandlerMask

                        --report-unsupported-elements-at-runtime
                        --allow-incomplete-classpath
                        --enable-url-protocols=http
                        -H:+ReportExceptionStackTraces
                        -H:EnableURLProtocols=http
                        -H:EnableURLProtocols=https


                        

                        

                        --trace-class-initialization=org.apache.log4j.Layout
                        --trace-class-initialization=java.beans.Introspector
                        --trace-class-initialization=com.sun.beans.introspect.ClassInfo

                        -Dio.netty.tryReflectionSetAccessible=true

                        --add-exports=java.base/java.nio=ALL-UNNAMED

                        --add-opens java.base/java.nio=ALL-UNNAMED



                    



                


                
                    
                        
                            native-image
                        
                        package
                    
                
            

            
                org.codehaus.mojo
                exec-maven-plugin
                3.0.0
                
                    
                        java-agent
                        
                            exec
                        
                        
                            java
                            ${project.build.directory}
                            
                                -classpath
                                
                                com.lang.Application
                            
                        

                    
                
            

        
    

上面注释掉的plug是用于生成jar的,所以生成jar时,需要把下面编译原生的plug注释掉,把生成jar的plug放开

直接idea上点击maven packeage 生成jar包

生成反射配置文件(注意配置好javahome和graavm)

不需要使用ms的控制台编译工具
./java -agentlib:native-image-agent=config-output-dir=E:\AAAA_CODE\new-eclipse-workspace\native-netty-log4j\src\main\resources\META-INF\native-image -jar E:\AAAA_CODE\new-eclipse-workspace\native-netty-log4j\target\native-image-js.jar

  • config-output-dir 指定反射配置文件输出的目录
  • maven项目的话,生成的配置文件必须放在resources\META-INF\native-image下

  • 可以看到,上面的指令执行后,jar会被执行一次,以便vm获取到反射信息
    E:\AAAA_CODE\new-eclipse-workspace\native-netty-log4j\src\main\resources\META-INF\native-image目录下也生成了反射配置文件

生成二进制

先把pom中生成jar的plug注释掉,打开生成二进制的plug
使用ms编译工具进入到项目根目录

执行 mvn -Pnative clean package

  • 生成二进制成功,可以看到还生成了相关需要的dll文件

  • 执行exe,启动速度非常快

注意:由于程序没有写死循环,所以执行完就退出控制台,可以先开一个控制台,再把exe拖到这个控制台执行就行了,否则你需要在程序中写个死循环,防止程序执行完就关掉

执行mvn -Pnative clean package 遇到的问题

  • 我遇到了万恶的should not reach here,但是也能正常生成EXE,先不管它就好。以后解决
  • 注意 由于反射时,需要用到不同的类,如果你的项目在编译二进制时 出现以下的报错提示
--initialize-at-build-time=java.beans.Introspector

--initialize-at-build-time 是指,在编译时 需要找这样的类,你只需要加到pom中即可

参考了这些

https://www.bookstack.cn/read/apache-dubbo-3.0-zh/917feda3752824d9.md
https://graalvm.github.io/native-build-tools/latest/maven-plugin.html
https://www.graalvm.org/22.1/reference-manual/native-image/Reflection/
https://blog.csdn.net/dlz00001/article/details/107254716
https://www.bianchengquan.com/article/223169.html