打包springboot graalvm原生镜像


GraalVM Native Image简介

  • GraalVM提供一种全新的方式让你发布及运行你的java应用,与传统的JVM相比,具备更小的内存占用合更快的启动速度。
  • 非常适合用容器来部署应用,适合Function as a service(FaaS)应用场景。
  • GrralVM使用AOT技术,在程序运行前将源代码编译为二进制的可执行的静态文件,并确定应用程序入口。
  • GraalVM本机映像是一个完整的、特定于平台的可执行文件。不需要为了运行本机映像而提供Java虚拟机。
  • 开始时间(以毫秒为单位)
  • 立即提供峰值性能,无需热身

示例项目

  • GetResourceRequest.java

    /**
     * 查询资源 request
     */
    @Data
    public class GetResourceRequest {
    
        /**
         * 资源类型:1、资源1,2、资源2
         */
        @Min(value = 1,message = "资源类型不能小于1")
        @Max(value = 2,message = "资源类型不能大于2")
        private int typeId;
    }
  • BaseResponse.java

    /**
     * 基础 response
     */
    @Data
    @NoArgsConstructor
    public class BaseResponse<T> {
    
        /**
         * 返回值code
         */
        private int code;
    
        /**
         * 错误消息
         */
        private String failMsg;
    
        /**
         * 数据
         */
        public T data;
    
        public BaseResponse(T data) {
            this.data = data;
            this.code = 0;
            this.failMsg = "success";
        }
    
        public boolean isSuccess() {
            return code == 0;
        }
    }
  • GetResourceResponse.java

    /**
     * 查询资源 response
     */
    @Data
    public class GetResourceResponse extends BaseResponse<GetResourceResponse.Resource> {
    
        public GetResourceResponse(String resource) {
            super(new Resource(resource));
        }
    
        /**
         * 资源
         */
        @Data
        public static class Resource {
            /**
             * 资源内容
             */
            String content;
    
            public Resource(String content) {
                this.content = content;
            }
        }
    }
  • IndexController.java

    package show.lmm.demo.springboot_aot.controller;
    
    import org.springframework.validation.annotation.Validated;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    import reactor.core.publisher.Mono;
    import show.lmm.demo.springboot_aot.util.FileUtils;
    import show.lmm.demo.springboot_aot.view.request.GetResourceRequest;
    import show.lmm.demo.springboot_aot.view.response.GetResourceResponse;
    
    @RequestMapping("/")
    @RestController
    public class IndexController {
    
        @GetMapping("/get_resource")
        public Mono<GetResourceResponse> getResource(@Validated GetResourceRequest info) {
            String resource = null;
            if (info.getTypeId() == 1) {
                resource = FileUtils.readAllText(this.getClass().getResourceAsStream("/config/demo.txt"));
            } else {
                resource = FileUtils.readAllText(this.getClass().getResourceAsStream("/config/demo2.txt"));
            }
            return Mono.just(new GetResourceResponse(resource));
        }
    }
    

报错及解决办法

No primary or single unique constructor found

  • 问题产生的原因:当请求url时,springboot会将参数转成java bean,用到了序列化。
  • 详细错误日志
    [springboot_aot] [or-http-epoll-2] a.w.r.e.AbstractErrorWebExceptionHandler : [18d5e511-1]  500 Server Error for HTTP GET "/get_resource?typeId=1"
    
    java.lang.IllegalStateException: No primary or single unique constructor found for class show.lmm.demo.springboot_aot.view.request.GetResourceRequest
            at org.springframework.beans.BeanUtils.getResolvableConstructor(BeanUtils.java:267) ~[na:na]
            Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException:
    Error has been observed at the following site(s):
            *__checkpoint ⇢ HTTP GET "/get_resource?typeId=1" [ExceptionHandlingWebHandler]
    Original Stack Trace:
                    at org.springframework.beans.BeanUtils.getResolvableConstructor(BeanUtils.java:267) ~[na:na]
                    at org.springframework.validation.DataBinder.createObject(DataBinder.java:924) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:6.1.4]
                    at org.springframework.validation.DataBinder.construct(DataBinder.java:903) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:6.1.4]
                    at org.springframework.web.bind.support.WebExchangeDataBinder.lambda$construct$0(WebExchangeDataBinder.java:88) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:6.1.4]
                    at reactor.core.publisher.FluxPeek$PeekSubscriber.onNext(FluxPeek.java:185) ~[na:na]
                    at reactor.core.publisher.FluxPeek$PeekSubscriber.onNext(FluxPeek.java:200) ~[na:na]
                    at reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:122) ~[na:na]
                    at reactor.core.publisher.MonoZip$ZipCoordinator.signal(MonoZip.java:297) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:3.6.3]
                    at reactor.core.publisher.MonoZip$ZipInner.onNext(MonoZip.java:478) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:3.6.3]
                    at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1865) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:3.6.3]
                    at reactor.core.publisher.MonoCacheTime$CoordinatorSubscriber.signalCached(MonoCacheTime.java:337) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:3.6.3]
                    at reactor.core.publisher.MonoCacheTime$CoordinatorSubscriber.onNext(MonoCacheTime.java:354) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:3.6.3]
                    at reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:2571) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:3.6.3]
                    at reactor.core.publisher.MonoCacheTime$CoordinatorSubscriber.onSubscribe(MonoCacheTime.java:293) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:3.6.3]
                    at reactor.core.publisher.MonoJust.subscribe(MonoJust.java:55) ~[na:na]
                    at reactor.core.publisher.MonoCacheTime.subscribeOrReturn(MonoCacheTime.java:143) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:3.6.3]
                    at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:63) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:3.6.3]
                    at reactor.core.publisher.MonoZip$ZipCoordinator.request(MonoZip.java:220) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:3.6.3]
                    at reactor.core.publisher.FluxMap$MapSubscriber.request(FluxMap.java:164) ~[na:na]
                    at reactor.core.publisher.FluxPeek$PeekSubscriber.request(FluxPeek.java:138) ~[na:na]
                    at reactor.core.publisher.FluxPeek$PeekSubscriber.request(FluxPeek.java:138) ~[na:na]
                    at reactor.core.publisher.MonoIgnoreElements$IgnoreElementsSubscriber.onSubscribe(MonoIgnoreElements.java:72) ~[na:na]
                    at reactor.core.publisher.FluxPeek$PeekSubscriber.onSubscribe(FluxPeek.java:171) ~[na:na]
                    at reactor.core.publisher.FluxPeek$PeekSubscriber.onSubscribe(FluxPeek.java:171) ~[na:na]
                    at reactor.core.publisher.FluxMap$MapSubscriber.onSubscribe(FluxMap.java:92) ~[na:na]
                    at reactor.core.publisher.MonoZip.subscribe(MonoZip.java:129) ~[na:na]
                    at reactor.core.publisher.Mono.subscribe(Mono.java:4563) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:3.6.3]
                    at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.subscribeNext(MonoIgnoreThen.java:265) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:3.6.3]
                    at reactor.core.publisher.MonoIgnoreThen.subscribe(MonoIgnoreThen.java:51) ~[na:na]
                    at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:76) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:3.6.3]
                    at reactor.core.publisher.MonoZip$ZipCoordinator.request(MonoZip.java:220) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:3.6.3]
                    at reactor.core.publisher.MonoFlatMap$FlatMapMain.request(MonoFlatMap.java:194) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:3.6.3]
                    at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.onSubscribe(MonoIgnoreThen.java:135) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:3.6.3]
                    at reactor.core.publisher.MonoFlatMap$FlatMapMain.onSubscribe(MonoFlatMap.java:117) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:3.6.3]
                    at reactor.core.publisher.MonoZip.subscribe(MonoZip.java:129) ~[na:na]
                    at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:76) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:3.6.3]
                    at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:53) ~[na:na]
                    at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.subscribeNext(MonoIgnoreThen.java:241) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:3.6.3]
                    at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.onComplete(MonoIgnoreThen.java:204) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:3.6.3]
                    at reactor.core.publisher.MonoFlatMap$FlatMapMain.onComplete(MonoFlatMap.java:189) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:3.6.3]
                    at reactor.core.publisher.Operators.complete(Operators.java:137) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:3.6.3]
                    at reactor.core.publisher.MonoZip.subscribe(MonoZip.java:121) ~[na:na]
                    at reactor.core.publisher.Mono.subscribe(Mono.java:4563) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:3.6.3]
                    at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.subscribeNext(MonoIgnoreThen.java:265) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:3.6.3]
                    at reactor.core.publisher.MonoIgnoreThen.subscribe(MonoIgnoreThen.java:51) ~[na:na]
                    at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:76) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:3.6.3]
                    at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:165) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:3.6.3]
                    at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:79) ~[na:na]
                    at reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onNext(FluxSwitchIfEmpty.java:74) ~[na:na]
                    at reactor.core.publisher.MonoNext$NextSubscriber.onNext(MonoNext.java:82) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:3.6.3]
                    at reactor.core.publisher.FluxConcatMapNoPrefetch$FluxConcatMapNoPrefetchSubscriber.innerNext(FluxConcatMapNoPrefetch.java:259) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:3.6.3]
                    at reactor.core.publisher.FluxConcatMap$ConcatMapInner.onNext(FluxConcatMap.java:865) ~[na:na]
                    at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:129) ~[na:na]
                    at reactor.core.publisher.MonoPeekTerminal$MonoTerminalPeekSubscriber.onNext(MonoPeekTerminal.java:180) ~[na:na]
                    at reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:2571) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:3.6.3]
                    at reactor.core.publisher.MonoPeekTerminal$MonoTerminalPeekSubscriber.request(MonoPeekTerminal.java:139) ~[na:na]
                    at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.request(FluxMapFuseable.java:171) ~[na:na]
                    at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.request(Operators.java:2331) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:3.6.3]
                    at reactor.core.publisher.FluxConcatMapNoPrefetch$FluxConcatMapNoPrefetchSubscriber.request(FluxConcatMapNoPrefetch.java:339) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:3.6.3]
                    at reactor.core.publisher.MonoNext$NextSubscriber.request(MonoNext.java:108) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:3.6.3]
                    at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.set(Operators.java:2367) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:3.6.3]
                    at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.onSubscribe(Operators.java:2241) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:3.6.3]
                    at reactor.core.publisher.MonoNext$NextSubscriber.onSubscribe(MonoNext.java:70) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:3.6.3]
                    at reactor.core.publisher.FluxConcatMapNoPrefetch$FluxConcatMapNoPrefetchSubscriber.onSubscribe(FluxConcatMapNoPrefetch.java:164) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:3.6.3]
                    at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:201) ~[na:na]
                    at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:83) ~[na:na]
                    at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:76) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:3.6.3]
                    at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:53) ~[na:na]
                    at reactor.core.publisher.Mono.subscribe(Mono.java:4563) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:3.6.3]
                    at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.subscribeNext(MonoIgnoreThen.java:265) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:3.6.3]
                    at reactor.core.publisher.MonoIgnoreThen.subscribe(MonoIgnoreThen.java:51) ~[na:na]
                    at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:76) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:3.6.3]
                    at reactor.core.publisher.MonoDeferContextual.subscribe(MonoDeferContextual.java:55) ~[na:na]
                    at reactor.netty.http.server.HttpServer$HttpServerHandle.onStateChange(HttpServer.java:1169) ~[na:na]
                    at reactor.netty.ReactorNetty$CompositeConnectionObserver.onStateChange(ReactorNetty.java:710) ~[na:na]
                    at reactor.netty.transport.ServerTransport$ChildObserver.onStateChange(ServerTransport.java:481) ~[na:na]
                    at reactor.netty.http.server.HttpServerOperations.onInboundNext(HttpServerOperations.java:652) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:1.1.16]
                    at reactor.netty.channel.ChannelOperationsHandler.channelRead(ChannelOperationsHandler.java:114) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:1.1.16]
                    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:4.1.107.Final]
                    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:4.1.107.Final]
                    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:4.1.107.Final]
                    at reactor.netty.http.server.HttpTrafficHandler.channelRead(HttpTrafficHandler.java:238) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:1.1.16]
                    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:442) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:4.1.107.Final]
                    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:4.1.107.Final]
                    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:4.1.107.Final]
                    at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:436) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:4.1.107.Final]
                    at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:346) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:4.1.107.Final]
                    at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:318) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:4.1.107.Final]
                    at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:251) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:4.1.107.Final]
                    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:442) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:4.1.107.Final]
                    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:4.1.107.Final]
                    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:4.1.107.Final]
                    at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:4.1.107.Final]
                    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:440) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:4.1.107.Final]
                    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:4.1.107.Final]
                    at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:4.1.107.Final]
                    at io.netty.channel.epoll.AbstractEpollStreamChannel$EpollStreamUnsafe.epollInReady(AbstractEpollStreamChannel.java:800) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:4.1.107.Final]
                    at io.netty.channel.epoll.EpollEventLoop.processReady(EpollEventLoop.java:509) ~[na:na]
                    at io.netty.channel.epoll.EpollEventLoop.run(EpollEventLoop.java:407) ~[na:na]
                    at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997) ~[na:na]
                    at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) ~[na:na]
                    at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) ~[na:na]
                    at java.base@21.0.2/java.lang.Thread.runWith(Thread.java:1596) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:na]
                    at java.base@21.0.2/java.lang.Thread.run(Thread.java:1583) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:na]
                    at org.graalvm.nativeimage.builder/com.oracle.svm.core.thread.PlatformThreads.threadStartRoutine(PlatformThreads.java:838) ~[show.lmm.demo.springboot_aot.SpringbootAotApplication:na]
                    at org.graalvm.nativeimage.builder/com.oracle.svm.core.posix.thread.PosixPlatformThreads.pthreadStartRoutine(PosixPlatformThreads.java:211) ~[na:na]
  • 解决方法:由于graalvm默认不支持序列化/反序列化,如需支持需要手动将需要序列化/反序列化的bean配置到reflect-config.json配置文件中

读取resource提示java.lang.NullPointerException

  • 问题产生的原因:graalvm不支持动态读取资源文件
  • 解决方法:将resources目录中的资源文件配置到resource-config.json配置文件中

springboot动态生成reflect和resource配置

  1. 实现RuntimeHintsRegistrar
    AotDemoRuntimeHints.java

    package show.lmm.demo.springboot_aot;
    
    import lombok.SneakyThrows;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.aot.hint.BindingReflectionHintsRegistrar;
    import org.springframework.aot.hint.ReflectionHints;
    import org.springframework.aot.hint.RuntimeHints;
    import org.springframework.aot.hint.RuntimeHintsRegistrar;
    import org.springframework.core.io.Resource;
    import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
    import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
    import org.springframework.core.type.classreading.MetadataReader;
    import org.springframework.lang.Nullable;
    import org.springframework.util.ClassUtils;
    
    @Slf4j
    public class AotDemoRuntimeHints implements RuntimeHintsRegistrar {
    
        @SneakyThrows
        @Nullable
        @Override
        public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
            BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar();
            PathMatchingResourcePatternResolver pathMatching = new PathMatchingResourcePatternResolver(classLoader);
            // 配置java bean reflect
            registerAotPackage(bindingRegistrar, pathMatching, hints.reflection(), "show.lmm.demo.springboot_aot.view");
            // 配置 资源文件
            hints.resources().registerPattern("config/*.txt");
        }
    
        /**
         * 注册AOT包
         */
        private void registerAotPackage(BindingReflectionHintsRegistrar bindingRegistrar,
                                        PathMatchingResourcePatternResolver pathMatching,
                                        ReflectionHints hints,
                                        String packageName
        ) throws Exception {
            CachingMetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory();
            String resourcePath = packageName.replaceAll("\\.", "/");
            resourcePath = String.format("classpath*:%s/**/*.class", resourcePath);
            Resource[] resources = pathMatching.getResources(resourcePath);
            for (Resource resource : resources) {
                String filename = resource.getFilename();
                if (filename != null && filename.contains(ClassUtils.CGLIB_CLASS_SEPARATOR)) {
                    // Ignore CGLIB-generated classes in the classpath
                    continue;
                }
                MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(resource);
                String className = metadataReader.getClassMetadata().getClassName();
                // 手动aot
                Class<?> classObj = Class.forName(className);
                bindingRegistrar.registerReflectionHints(hints, classObj);
            }
        }
    }
  2. 配置resources\META-INF\spring\aot.factories

    org.springframework.aot.hint.RuntimeHintsRegistrar= \
    show.lmm.demo.springboot_aot.AotDemoRuntimeHints

示例

https://gitee.com/luoye/examples/tree/main/springboot_aot


文章作者: Ming Ming Liu
文章链接: https://www.lmm.show/33/
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Ming Ming Liu !
  目录