1.配置环境

首先下载graalvm并配置环境变量,由于网络原因我们还需在github下载native-image

这里使用的是

graalvm-ce-java17-windows-amd64-22.3.2.zip

native-image-installable-svm-java17-windows-amd64-22.3.2.jar

打开终端(cmd或者powershell)若网络环境比较好则直接安装

联网安装
gu install native-image
本地安装
gu install --file native-image-installable-svm-java17-windows-amd64-22.3.2.jar

验证是否安装成功

$ native-image
Please specify options for native-image building or use --help for more info.

1.windows :下载VisualStudio,安装时选择c++的桌面开发

安装完会有x64 Native Tools Command Prompt for VS 2022工具,打开此工具进入到我们需要打包的jar文件的目录下

1.配置环境变量

需要修改三个环境变量PathINCLUDElib

  • 1、 Path:添加如下值

    • C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.33.31629\bin\Hostx64\x64
  • 2、新建INCLUDE环境变量:值为

  • C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.33.31629\include;
    C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\shared;
    C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\ucrt;
    C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\um;
    C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\winrt
    

    3、新建lib环境变量:值为

    C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.33.31629\lib\x64;
    C:\Program Files (x86)\Windows Kits\10\Lib\10.0.19041.0\um\x64;
    C:\Program Files (x86)\Windows Kits\10\Lib\10.0.19041.0\ucrt\x64
    

    其中环境变量为VisualStudio安装目录下的头文件以及库

2.linux 在linux平台下需要gcc等环境

sudo yum install gcc glibc-devel zlib-devel
2.打包

打包jar命令格式为

native-image -cp [jar包名] [全限定主类名] [-o可选,输出] [输出名] [--no-fallback 可选,可以在没有jdk环境的机器上运行]
或者
native-image -jar [jar包] [-o可选,输出] [输出名] [--no-fallback 可选,可以在没有jdk环境的机器上运行]

例:

#编译jar包
D:\abc>ls
TestNative.jar  Tetris.jar  jadx-gui-devs.jar

D:\abc>native-image -cp jadx-gui-devs.jar jadx.gui.JadxGUI -o jadx-gui
#编译某个类【必须有main入口方法,否则无法编译】
native-image -cp .\classes org.example.App
打包maven项目

直接maven clean->complie->package就ok了

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>graalvmTest</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <graalvm.version>23.1.2</graalvm.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.graalvm.sdk</groupId>
            <artifactId>graal-sdk</artifactId>
            <version>${graalvm.version}</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.graalvm.nativeimage</groupId>
                <artifactId>native-image-maven-plugin</artifactId>
                <version>21.2.0</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>native-image</goal>
                        </goals>
                        <phase>package</phase>
                    </execution>
                </executions>
                <configuration>
                    <skip>false</skip>
					<imageName>${project.artifactId}</imageName>
                    <mainClass>主函数全面限类名</mainClass>
                    <buildArgs>
                        --no-fallback
                    </buildArgs>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

复杂项目的问题

打包的exe如果有反射等用法,很容易发生ClassNotFound的报错

Graalvm通过静态分析提前编译来为Java应用程序构建高度优化的本机可执行文件,这就需要在编译时就知道所有的程序类型,而java中的反射、动态代理等功能,在编译时不确定具体的类型,所以在使用GraalVm构建native image前需要通过配置列出反射可见的所有类型。而程序内置提供了agentlib

使用agentlib打包跟踪jvm生成配置文件
java -agentlib:native-image-agent=config-output-dir=.\config\ -jar [jar包]
会在config目录下生成json配置文件
|-D:\ecj\ECJ\target\config
	|-agent-extracted-predefined-classes
	|-jni-config.json
	|-predefined-classes-config.json
	|-proxy-config.json
	|-reflect-config.json
	|-resource-config.json
	|-serialization-config.json

META-INF中的native-image中新增带有groupid和artifactId的路径,并且将配置文件粘贴

结构
META-INF
    ├─maven
    │  └─org.eclipse
    │      └─ECJ
    └─native-image
        ├─org.eclipse <groupId>
        └─ECJ <artifactId>
        	|-jni-config.json
            |-predefined-classes-config.json
            |-proxy-config.json
            |-reflect-config.json
            |-resource-config.json
            |-serialization-config.json
        	

打包

native-image -jar  [jar包] --no-fallback

如果出现报错

Error:Class initialization of io.netty.util.internal.logging.Log4JLogger failed. Use the option --initialize-at-run-time=io.netty.util.internal.logging.logging.Log4JLogger to explicitly requeset delayed initialization of this class

则需要添加参数

native-image -jar  [jar包] --no-fallback --initialize-at-run-time=io.netty.util.internal.logging.logging.Log4JLogger --allow-incomplete-classpath
3.整合SpringBoot
1.pom.xml文件配置
	
		<!--
    		graal 官方 SDK ,是必须的,不要删除,否则会在执行 mvnw -Pnative clean native:compile 命令时报类似这样的错:
    		package org.graalvm.nativeimage.hosted does not exist
    	-->
  <dependencies>
    	<dependency>
      		<groupId>org.graalvm.sdk</groupId>
      		<artifactId>graal-sdk</artifactId>
      		<version>23.1.2</version>
      		<scope>provided</scope>
    	</dependency>
  </dependencies>

 <build>
        <!-- 以下资源配置是为了确保 mybatis-plus 对应的 *Mapper.xml 文件都打包进去了 -->
<!--        <resources>-->
<!--            <resource>-->
<!--                <directory>src/main/resources</directory>-->
<!--            </resource>-->
<!--            <resource>-->
<!--                <directory>src/main/java</directory>-->
<!--                <includes>-->
<!--                    <include>**/*.xml</include>-->
<!--                </includes>-->
<!--            </resource>-->
<!--        </resources>-->
        <plugins>
            <plugin>
                <groupId>org.graalvm.buildtools</groupId>
                <artifactId>native-maven-plugin</artifactId>
                <configuration>
                    <quickBuild>true</quickBuild>
                    <buildArgs combine.children="append">
                        <!-- 支持 http 协议 -->
                        <buildArg>--enable-url-protocols=http</buildArg>
                        <!-- 用于解决数据库中文乱码问题 -->
                        <buildArg>-H:+AddAllCharsets</buildArg>
                        <!-- GraalVM native image 默认不支持 Lambda 表达式,为了让它支持,需要把用到了 Lambda 表达式的类						都集中注册一下  -->
                        <buildArg>
                            --features=com.bingbaihanji.springbooth2basedemo.config.LambdaRegistrationFeature
                        </buildArg>
                    </buildArgs>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
2.注册lambda表达式配置类

其中com.bingbaihanji.springbooth2basedemo.config.LambdaRegistrationFeature配置类为

package com.bingbaihanji.springbooth2basedemo.config;


import com.bingbaihanji.springbooth2basedemo.Application;
import com.bingbaihanji.springbooth2basedemo.controller.AreaController;
import com.bingbaihanji.springbooth2basedemo.controller.IndexController;
import com.bingbaihanji.springbooth2basedemo.pojo.Area;
import com.bingbaihanji.springbooth2basedemo.pojo.Users;
import org.graalvm.nativeimage.hosted.Feature;
import org.graalvm.nativeimage.hosted.RuntimeSerialization;

/**
 * lambda 表达式注入到 graal 中
 *
 * @author bingbaihanji
 * @date 2023/8/18 11:53
 */
public class LambdaRegistrationFeature implements Feature {

  @Override
  public void duringSetup(DuringSetupAccess access) {
    // 这里需要将lambda表达式所使用的成员类都注册上来,具体情况视项目情况而定,一般扫描@Controller和@Service的会多点.
    RuntimeSerialization.registerLambdaCapturingClass(Application.class);
    RuntimeSerialization.registerLambdaCapturingClass(AreaController.class);
    RuntimeSerialization.registerLambdaCapturingClass(IndexController.class);
    RuntimeSerialization.registerLambdaCapturingClass(Area.class);
    RuntimeSerialization.registerLambdaCapturingClass(Users.class);
    RuntimeSerialization.registerLambdaCapturingClass(WebMvcConfigurers.class);
  }
}
3.注册mybatis-plus配置类(若项目使用mybatis-plus则需要)
import com.baomidou.mybatisplus.annotation.IEnum;
import com.baomidou.mybatisplus.core.MybatisParameterHandler;
import com.baomidou.mybatisplus.core.MybatisXMLLanguageDriver;
import com.baomidou.mybatisplus.core.conditions.AbstractWrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.handlers.CompositeEnumTypeHandler;
import com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.core.toolkit.support.SerializedLambda;
import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler;
import com.baomidou.mybatisplus.extension.handlers.GsonTypeHandler;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import org.apache.commons.logging.LogFactory;
import org.apache.ibatis.annotations.DeleteProvider;
import org.apache.ibatis.annotations.InsertProvider;
import org.apache.ibatis.annotations.SelectProvider;
import org.apache.ibatis.annotations.UpdateProvider;
import org.apache.ibatis.cache.decorators.FifoCache;
import org.apache.ibatis.cache.decorators.LruCache;
import org.apache.ibatis.cache.decorators.SoftCache;
import org.apache.ibatis.cache.decorators.WeakCache;
import org.apache.ibatis.cache.impl.PerpetualCache;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.resultset.ResultSetHandler;
import org.apache.ibatis.executor.statement.BaseStatementHandler;
import org.apache.ibatis.executor.statement.RoutingStatementHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.javassist.util.proxy.ProxyFactory;
import org.apache.ibatis.javassist.util.proxy.RuntimeSupport;
import org.apache.ibatis.logging.Log;
import org.apache.ibatis.logging.commons.JakartaCommonsLoggingImpl;
import org.apache.ibatis.logging.jdk14.Jdk14LoggingImpl;
import org.apache.ibatis.logging.log4j2.Log4j2Impl;
import org.apache.ibatis.logging.nologging.NoLoggingImpl;
import org.apache.ibatis.logging.slf4j.Slf4jImpl;
import org.apache.ibatis.logging.stdout.StdOutImpl;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.reflection.TypeParameterResolver;
import org.apache.ibatis.scripting.defaults.RawLanguageDriver;
import org.apache.ibatis.scripting.xmltags.XMLLanguageDriver;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.mapper.MapperFactoryBean;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.aot.hint.MemberCategory;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution;
import org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor;
import org.springframework.beans.factory.aot.BeanRegistrationExcludeFilter;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor;
import org.springframework.beans.factory.support.RegisteredBean;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportRuntimeHints;
import org.springframework.core.ResolvableType;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * This configuration will move to mybatis-spring-native.
 */
@Configuration(proxyBeanMethods = false)
@ImportRuntimeHints(MyBatisNativeConfiguration.MyBaitsRuntimeHintsRegistrar.class)
public class MyBatisNativeConfiguration {

    @Bean
    static MyBatisMapperFactoryBeanPostProcessor myBatisMapperFactoryBeanPostProcessor() {
        return new MyBatisMapperFactoryBeanPostProcessor();
    }

    @Bean
    MyBatisBeanFactoryInitializationAotProcessor myBatisBeanFactoryInitializationAotProcessor() {
        return new MyBatisBeanFactoryInitializationAotProcessor();
    }

    static class MyBaitsRuntimeHintsRegistrar implements RuntimeHintsRegistrar {

        @Override
        public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
            Stream.of(
                            RawLanguageDriver.class,
                            XMLLanguageDriver.class,
                            MybatisXMLLanguageDriver.class,
                            RuntimeSupport.class,
                            ProxyFactory.class,
                            Slf4jImpl.class,
                            Log.class,
                            JakartaCommonsLoggingImpl.class,
                            Log4j2Impl.class,
                            Jdk14LoggingImpl.class,
                            StdOutImpl.class,
                            NoLoggingImpl.class,
                            SqlSessionFactory.class,
                            PerpetualCache.class,
                            FifoCache.class,
                            LruCache.class,
                            SoftCache.class,
                            WeakCache.class,
                            SqlSessionFactoryBean.class,
                            MybatisSqlSessionFactoryBean.class,
                            ArrayList.class,
                            HashMap.class,
                            TreeSet.class,
                            HashSet.class)
                    .forEach(x -> hints.reflection().registerType(x, MemberCategory.values()));
            Stream.of("org/apache/ibatis/builder/xml/*.dtd", "org/apache/ibatis/builder/xml/*.xsd")
                    .forEach(hints.resources()::registerPattern);

            hints.serialization().registerType(SerializedLambda.class);
            hints.serialization().registerType(SFunction.class);
            hints.serialization().registerType(java.lang.invoke.SerializedLambda.class);
            hints.reflection().registerType(SFunction.class);
            hints.reflection().registerType(SerializedLambda.class);
            hints.reflection().registerType(java.lang.invoke.SerializedLambda.class);
            hints.reflection().registerType(org.apache.ibatis.logging.LogFactory.class);
            hints.reflection().registerType(Slf4jImpl.class);

            hints.proxies().registerJdkProxy(StatementHandler.class);
            hints.proxies().registerJdkProxy(Executor.class);
            hints.proxies().registerJdkProxy(ResultSetHandler.class);
            hints.proxies().registerJdkProxy(ParameterHandler.class);

            hints.reflection().registerType(AbstractWrapper.class, MemberCategory.values());
            hints.reflection().registerType(LambdaQueryWrapper.class, MemberCategory.values());
            hints.reflection().registerType(LambdaUpdateWrapper.class, MemberCategory.values());
            hints.reflection().registerType(UpdateWrapper.class, MemberCategory.values());
            hints.reflection().registerType(QueryWrapper.class, MemberCategory.values());

            // hints.reflection().registerType(org.apache.ibatis.logging.LogFactory.class, MemberCategory.values());

            hints.reflection().registerType(BoundSql.class, MemberCategory.DECLARED_FIELDS);
            hints
                    .reflection()
                    .registerType(RoutingStatementHandler.class, MemberCategory.DECLARED_FIELDS);
            hints.reflection().registerType(BaseStatementHandler.class, MemberCategory.DECLARED_FIELDS);
            hints
                    .reflection()
                    .registerType(MybatisParameterHandler.class, MemberCategory.DECLARED_FIELDS);

            hints.reflection().registerType(IEnum.class, MemberCategory.INVOKE_PUBLIC_METHODS);
            // register typeHandler
            hints
                    .reflection()
                    .registerType(CompositeEnumTypeHandler.class, MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS);
            hints
                    .reflection()
                    .registerType(FastjsonTypeHandler.class, MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS);
            hints
                    .reflection()
                    .registerType(GsonTypeHandler.class, MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS);
            hints
                    .reflection()
                    .registerType(JacksonTypeHandler.class, MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS);
            hints
                    .reflection()
                    .registerType(MybatisEnumTypeHandler.class, MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS);
        }
    }

    static class MyBatisBeanFactoryInitializationAotProcessor
            implements BeanFactoryInitializationAotProcessor, BeanRegistrationExcludeFilter {

        private final Set<Class<?>> excludeClasses = new HashSet<>();

        MyBatisBeanFactoryInitializationAotProcessor() {
            excludeClasses.add(MapperScannerConfigurer.class);
        }

        @Override
        public boolean isExcludedFromAotProcessing(RegisteredBean registeredBean) {
            return excludeClasses.contains(registeredBean.getBeanClass());
        }

        @Override
        public BeanFactoryInitializationAotContribution processAheadOfTime(
                ConfigurableListableBeanFactory beanFactory) {
            String[] beanNames = beanFactory.getBeanNamesForType(MapperFactoryBean.class);
            if (beanNames.length == 0) {
                return null;
            }
            return (context, code) -> {
                RuntimeHints hints = context.getRuntimeHints();
                for (String beanName : beanNames) {
                    BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName.substring(1));
                    PropertyValue mapperInterface =
                            beanDefinition.getPropertyValues().getPropertyValue("mapperInterface");
                    if (mapperInterface != null && mapperInterface.getValue() != null) {
                        Class<?> mapperInterfaceType = (Class<?>) mapperInterface.getValue();
                        if (mapperInterfaceType != null) {
                            registerReflectionTypeIfNecessary(mapperInterfaceType, hints);
                            hints.proxies().registerJdkProxy(mapperInterfaceType);
                            hints
                                    .resources()
                                    .registerPattern(mapperInterfaceType.getName().replace('.', '/').concat(".xml"));
                            registerMapperRelationships(mapperInterfaceType, hints);
                        }
                    }
                }
            };
        }

        private void registerReflectionTypeIfNecessary(Class<?> type, RuntimeHints hints) {
            if (!type.isPrimitive() && !type.getName().startsWith("java")) {
                hints.reflection().registerType(type, MemberCategory.values());
            }
        }

        private void registerMapperRelationships(Class<?> mapperInterfaceType, RuntimeHints hints) {
            Method[] methods = ReflectionUtils.getAllDeclaredMethods(mapperInterfaceType);
            for (Method method : methods) {
                if (method.getDeclaringClass() != Object.class) {
                    ReflectionUtils.makeAccessible(method);
                    registerSqlProviderTypes(
                            method, hints, SelectProvider.class, SelectProvider::value, SelectProvider::type);
                    registerSqlProviderTypes(
                            method, hints, InsertProvider.class, InsertProvider::value, InsertProvider::type);
                    registerSqlProviderTypes(
                            method, hints, UpdateProvider.class, UpdateProvider::value, UpdateProvider::type);
                    registerSqlProviderTypes(
                            method, hints, DeleteProvider.class, DeleteProvider::value, DeleteProvider::type);
                    Class<?> returnType =
                            MyBatisMapperTypeUtils.resolveReturnClass(mapperInterfaceType, method);
                    registerReflectionTypeIfNecessary(returnType, hints);
                    MyBatisMapperTypeUtils.resolveParameterClasses(mapperInterfaceType, method)
                            .forEach(x -> registerReflectionTypeIfNecessary(x, hints));
                }
            }
        }

        @SafeVarargs
        private <T extends Annotation> void registerSqlProviderTypes(
                Method method,
                RuntimeHints hints,
                Class<T> annotationType,
                Function<T, Class<?>>... providerTypeResolvers) {
            for (T annotation : method.getAnnotationsByType(annotationType)) {
                for (Function<T, Class<?>> providerTypeResolver : providerTypeResolvers) {
                    registerReflectionTypeIfNecessary(providerTypeResolver.apply(annotation), hints);
                }
            }
        }
    }

    static class MyBatisMapperTypeUtils {
        private MyBatisMapperTypeUtils() {
            // NOP
        }

        static Class<?> resolveReturnClass(Class<?> mapperInterface, Method method) {
            Type resolvedReturnType = TypeParameterResolver.resolveReturnType(method, mapperInterface);
            return typeToClass(resolvedReturnType, method.getReturnType());
        }

        static Set<Class<?>> resolveParameterClasses(Class<?> mapperInterface, Method method) {
            return Stream.of(TypeParameterResolver.resolveParamTypes(method, mapperInterface))
                    .map(x -> typeToClass(x, x instanceof Class ? (Class<?>) x : Object.class))
                    .collect(Collectors.toSet());
        }

        private static Class<?> typeToClass(Type src, Class<?> fallback) {
            Class<?> result = null;
            if (src instanceof Class<?>) {
                if (((Class<?>) src).isArray()) {
                    result = ((Class<?>) src).getComponentType();
                } else {
                    result = (Class<?>) src;
                }
            } else if (src instanceof ParameterizedType) {
                ParameterizedType parameterizedType = (ParameterizedType) src;
                int index =
                        (parameterizedType.getRawType() instanceof Class
                                && Map.class.isAssignableFrom((Class<?>) parameterizedType.getRawType())
                                && parameterizedType.getActualTypeArguments().length > 1)
                                ? 1
                                : 0;
                Type actualType = parameterizedType.getActualTypeArguments()[index];
                result = typeToClass(actualType, fallback);
            }
            if (result == null) {
                result = fallback;
            }
            return result;
        }
    }

    static class MyBatisMapperFactoryBeanPostProcessor
            implements MergedBeanDefinitionPostProcessor, BeanFactoryAware {

        private static final org.apache.commons.logging.Log LOG =
                LogFactory.getLog(MyBatisMapperFactoryBeanPostProcessor.class);

        private static final String MAPPER_FACTORY_BEAN = "org.mybatis.spring.mapper.MapperFactoryBean";

        private ConfigurableBeanFactory beanFactory;

        @Override
        public void setBeanFactory(BeanFactory beanFactory) {
            this.beanFactory = (ConfigurableBeanFactory) beanFactory;
        }

        @Override
        public void postProcessMergedBeanDefinition(
                RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
            if (ClassUtils.isPresent(MAPPER_FACTORY_BEAN, this.beanFactory.getBeanClassLoader())) {
                resolveMapperFactoryBeanTypeIfNecessary(beanDefinition);
            }
        }

        private void resolveMapperFactoryBeanTypeIfNecessary(RootBeanDefinition beanDefinition) {
            if (!beanDefinition.hasBeanClass()
                    || !MapperFactoryBean.class.isAssignableFrom(beanDefinition.getBeanClass())) {
                return;
            }
            if (beanDefinition.getResolvableType().hasUnresolvableGenerics()) {
                Class<?> mapperInterface = getMapperInterface(beanDefinition);
                if (mapperInterface != null) {
                    // Exposes a generic type information to context for prevent early initializing
                    ConstructorArgumentValues constructorArgumentValues = new ConstructorArgumentValues();
                    constructorArgumentValues.addGenericArgumentValue(mapperInterface);
                    beanDefinition.setConstructorArgumentValues(constructorArgumentValues);
                    beanDefinition.setTargetType(
                            ResolvableType.forClassWithGenerics(beanDefinition.getBeanClass(), mapperInterface));
                }
            }
        }

        private Class<?> getMapperInterface(RootBeanDefinition beanDefinition) {
            try {
                return (Class<?>) beanDefinition.getPropertyValues().get("mapperInterface");
            } catch (Exception e) {
                LOG.debug("Fail getting mapper interface type.", e);
                return null;
            }
        }
    }
}

4.开始编译

在idea中勾选maven->配置文件->native,然后package打包,选择插件->native->native:compile-no-fork

即可打包成功

也可以直接进入到项目目录使用命令来打包

mvn -Pnative native:compile-no-fork -f pom.xml

或者

mvn -Pnative clean native:compile

若在windows下出现类似

Execution of D:\develop\Graalvm\GeaalVm_windows\graalvm-ce-java17-22.3.2\bin\native-image.cmd @target\tmp\native-image-10812911054789043447.args returned non-zero result

的错误,可以将项目目录下的target\tmp\native-image-10812911054789043447.args文件里边的路径符号\\替换为/

然后执行native-image.cmd @target\tmp\native-image-10812911054789043447.args命令即可;

或者直接将native-image-10812911054789043447.args文件里边的文本参数改成单行,直接复制粘贴到native-image

命令后边执行即可。

人生不作安期生,醉入东海骑长鲸