Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

增加对 lambda 表达式的支持 #5594

Closed
wants to merge 2 commits into from
Closed

Conversation

z744489075
Copy link

@z744489075 z744489075 commented Aug 18, 2023

该Pull Request关联的Issue

#5527 (comment)

修改描述

增加对 lambda 表达式的支持

1.在使用了lambda 的类上增加注解 @GraalReflectionAotHints
2.增加graal Feature


package com.maishi.common.config;

import com.baomidou.mybatisplus.extension.aot.AotUtils;
import org.graalvm.nativeimage.hosted.Feature;
import org.graalvm.nativeimage.hosted.RuntimeSerialization;

import java.util.List;

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


    @Override
    public void duringSetup(DuringSetupAccess access) {
        //RuntimeSerialization.registerLambdaCapturingClass(AppAlarmLevelSubscribeController.class);

        //参数是父包, 会扫描有写 @GraalReflectionAotHints 的类
        List<Class<?>> graalAotHints = AotUtils.getGraalAotHints(List.of("com.maishi"));

        graalAotHints.forEach(RuntimeSerialization::registerLambdaCapturingClass);

    }
}


3.在pom.xml 文件增加 Feature,灵魂是这一句 --features=com.maishi.common.config.LambdaRegistrationFeature

<plugin>
                <groupId>org.graalvm.buildtools</groupId>
                <artifactId>native-maven-plugin</artifactId>
                <configuration>
                    <buildArgs combine.children="append">
                        <!--<buildArg>-enable-url-protocols=http</buildArg>-->
                        <buildArg>-H:+AddAllCharsets</buildArg>
                        <buildArg>--features=com.maishi.common.config.LambdaRegistrationFeature</buildArg>
                    </buildArgs>
                </configuration>
            </plugin>

其他就不说了.该咋样就咋样

@z744489075 z744489075 changed the title 增加对 lambda 表达是的支持 增加对 lambda 表达式的支持 Aug 18, 2023
@nieqiurong
Copy link
Contributor

感谢,方案是可行的,但感觉registerLambdaCapturingClass还是由用户控制会好点,一般把controller和service登记上的人会多点,如果都依靠自定义注解注册的话,到时标记的注解太多了,这个我先更新至示例里面,后面看看方案改进.

@z744489075
Copy link
Author

感谢,方案是可行的,但感觉registerLambdaCapturingClass还是由用户控制会好点,一般把controller和service登记上的人会多点,如果都依靠自定义注解注册的话,到时标记的注解太多了,这个我先更新至示例里面,后面看看方案改进.

嗯,你们看咯,由于AOT破坏了代码的一致性,这个是我能想到最傻瓜,也最容易的方式,以前redis AOT bean的问题我是写了一个工具类每次发布的时候重新生成下引用,但是太容易忘记,导致redis报错,所有的controller和service标记上会增加点内存但是不会很多。

@yinyuncan
Copy link

我也遇到了lambda表达式支持问题,感谢@z744489075提供思路,我优化了一下直接改成了不要注解形式的扫描,然后注册进去

import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.core.toolkit.support.SerializedLambda;
import com.baomidou.mybatisplus.extension.service.IService;
import org.graalvm.nativeimage.hosted.Feature;
import org.graalvm.nativeimage.hosted.RuntimeSerialization;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.type.filter.AssignableTypeFilter;
import org.springframework.core.type.filter.TypeFilter;
import org.springframework.util.ClassUtils;

import java.util.ArrayList;
import java.util.List;
/**
 * 用于注册graalvm lambda序列化的类
 *
 * 感谢z744489075提供的思路:https://github.com/baomidou/mybatis-plus/pull/5594
 * @author  yun.can
 * @since  2023/09/15
 */
public class RuntimeRegistrationFeature implements Feature {
	/**
	 * 找到某个包下面指定的父类的所有子类
	 * @param packageName 包名
	 * @param superClass 父类
	 * @return 子类集合
	 */
	public static List<Class<?>> findClasses(String packageName, Class<?> superClass) {
		ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
		TypeFilter filter = new AssignableTypeFilter(superClass);

		scanner.addIncludeFilter(filter);

		List<Class<?>> classes = new ArrayList<>();
		String basePackage = ClassUtils.convertClassNameToResourcePath(packageName);
		for (BeanDefinition candidate : scanner.findCandidateComponents(basePackage)) {
			try {
				Class<?> clazz = Class.forName(candidate.getBeanClassName());
				classes.add(clazz);
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
				// 处理异常
			}
		}

		return classes;
	}

	@Override
	public void duringSetup(Feature.DuringSetupAccess access) {
//		扫描指定包下IService的字类(实现类),然后全部注册到graalvm lamda 序列化中
		RuntimeRegistrationFeature.findClasses("cn.yimakeji", IService.class)
			.forEach(RuntimeSerialization::registerLambdaCapturingClass);
		RuntimeSerialization.register(SerializedLambda.class, SFunction.class);
	}
}

我目前已经用在我项目中了,非常棒

@yinyuncan
Copy link

我也遇到了lambda表达式支持问题,感谢@z744489075提供思路,我优化了一下直接改成了不要注解形式的扫描,然后注册进去

import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.core.toolkit.support.SerializedLambda;
import com.baomidou.mybatisplus.extension.service.IService;
import org.graalvm.nativeimage.hosted.Feature;
import org.graalvm.nativeimage.hosted.RuntimeSerialization;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.type.filter.AssignableTypeFilter;
import org.springframework.core.type.filter.TypeFilter;
import org.springframework.util.ClassUtils;

import java.util.ArrayList;
import java.util.List;
/**
 * 用于注册graalvm lambda序列化的类
 *
 * 感谢z744489075提供的思路:https://github.com/baomidou/mybatis-plus/pull/5594
 * @author  yun.can
 * @since  2023/09/15
 */
public class RuntimeRegistrationFeature implements Feature {
	/**
	 * 找到某个包下面指定的父类的所有子类
	 * @param packageName 包名
	 * @param superClass 父类
	 * @return 子类集合
	 */
	public static List<Class<?>> findClasses(String packageName, Class<?> superClass) {
		ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
		TypeFilter filter = new AssignableTypeFilter(superClass);

		scanner.addIncludeFilter(filter);

		List<Class<?>> classes = new ArrayList<>();
		String basePackage = ClassUtils.convertClassNameToResourcePath(packageName);
		for (BeanDefinition candidate : scanner.findCandidateComponents(basePackage)) {
			try {
				Class<?> clazz = Class.forName(candidate.getBeanClassName());
				classes.add(clazz);
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
				// 处理异常
			}
		}

		return classes;
	}

	@Override
	public void duringSetup(Feature.DuringSetupAccess access) {
//		扫描指定包下IService的字类(实现类),然后全部注册到graalvm lamda 序列化中
		RuntimeRegistrationFeature.findClasses("cn.yimakeji", IService.class)
			.forEach(RuntimeSerialization::registerLambdaCapturingClass);
		RuntimeSerialization.register(SerializedLambda.class, SFunction.class);
	}
}

我目前已经用在我项目中了,非常棒

参数忘记给了,需要在native-image编译时添加spring相关类的参数,否则会造成编译失败

--initialize-at-build-time=org.slf4j.LoggerFactory,ch.qos.logback,org.springframework.core.annotation.AnnotationUtils,org.springframework.util.PropertyPlaceholderHelper,org.springframework.util.ClassUtils,org.springframework.core.annotation.PackagesAnnotationFilter,org.springframework.core.annotation.AnnotationTypeMappings,org.springframework.core.annotation.AnnotationFilter$1,org.springframework.core.annotation.AnnotationFilter$2,org.springframework.core.NativeDetector,org.springframework.core.annotation.MergedAnnotations$Search,org.springframework.core.io.support.PathMatchingResourcePatternResolver,org.springframework.core.SpringProperties,org.springframework.core.annotation.AttributeMethods,org.springframework.core.annotation.AnnotationFilter,org.springframework.util.AntPathMatcher,org.apache.commons.logging.LogAdapter,org.springframework.core.annotation.TypeMappedAnnotations,org.springframework.util.ReflectionUtils,org.springframework.util.AntPathMatcher$AntPathStringMatcher,org.springframework.core.annotation.RepeatableContainers$StandardRepeatableContainers,org.springframework.core.annotation.TypeMappedAnnotation,org.apache.commons.logging.LogAdapter$Slf4jLocationAwareLog,org.springframework.context.index.CandidateComponentsIndexLoader,org.springframework.core.annotation.AnnotationsScanner,org.springframework.core.annotation.AnnotationTypeMapping,org.springframework.util.ConcurrentReferenceHashMap,org.springframework.beans.BeanUtils,org.springframework.context.annotation.ConfigurationClassUtils,org.springframework.core.KotlinDetector,org.springframework.core.annotation.MergedAnnotationCollectors

以下这个是我完整配置

<plugins>
                    <plugin>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-maven-plugin</artifactId>
                        <extensions>true</extensions>
                        <configuration>
                            <profiles>
                                <profile>native</profile>
                            </profiles>
                            <!--                            <generatedResources>${project.build.directory}</generatedResources>-->
                            <!--                            <classifier>${repackage.classifier}</classifier>-->
                            <image>
                                <builder>paketobuildpacks/builder:tiny</builder>
                                <!--                                <builder>gcr.io/paketo-buildpacks/native-image</builder>-->
                                <!--docker-image配置:https://github.com/paketo-buildpacks/spring-boot-->
                                <env>
                                    <BP_NATIVE_IMAGE>true</BP_NATIVE_IMAGE>
                                    <!--配置代理-->
                                    <HTTP_PROXY>http://192.168.1.49:7890</HTTP_PROXY>
                                    <HTTPS_PROXY>http://192.168.1.49:7890</HTTPS_PROXY>
                                    <BP_JVM_VERSION>${java.version}</BP_JVM_VERSION>
                                    <!--                                    <BP_BINARY_COMPRESSION_METHOD>upx</BP_BINARY_COMPRESSION_METHOD>-->
                                    <BP_NATIVE_IMAGE_BUILD_ARGUMENTS>
                                        --verbose
                                        --enable-https
                                        --enable-http
                                        --initialize-at-build-time=sun.instrument.InstrumentationImpl
                                        --add-opens=java.base/java.nio=ALL-UNNAMED
                                        --add-opens=java.base/java.lang=ALL-UNNAMED
                                        --add-opens=java.base/java.text=ALL-UNNAMED
                                        --add-opens=java.base/java.net=ALL-UNNAMED
                                        --add-opens=java.base/java.util.concurrent=ALL-UNNAMED
                                        --add-opens=java.base/java.io=ALL-UNNAMED
                                        --add-opens=java.base/java.util=ALL-UNNAMED
                                        --add-opens=java.base/java.math=ALL-UNNAMED
                                        --add-opens=java.base/jdk.internal.misc=ALL-UNNAMED
                                        --add-opens=java.base/jdk.internal.ref=ALL-UNNAMED
                                        --trace-class-initialization=ch.qos.logback.classic.Logger,org.springframework.core.annotation.AnnotationUtils,org.springframework.util.PropertyPlaceholderHelper,org.springframework.util.ClassUtils,org.springframework.core.annotation.PackagesAnnotationFilter,org.springframework.core.annotation.AnnotationTypeMappings,org.springframework.core.annotation.AnnotationFilter$1,org.springframework.core.annotation.AnnotationFilter$2,org.springframework.core.NativeDetector,org.springframework.core.annotation.MergedAnnotations$Search,org.springframework.core.io.support.PathMatchingResourcePatternResolver,org.springframework.core.SpringProperties,org.springframework.core.annotation.AttributeMethods,org.springframework.core.annotation.AnnotationFilter,org.springframework.util.AntPathMatcher,org.apache.commons.logging.LogAdapter,org.springframework.core.annotation.TypeMappedAnnotations,org.springframework.util.ReflectionUtils,org.springframework.util.AntPathMatcher$AntPathStringMatcher,org.springframework.core.annotation.RepeatableContainers$StandardRepeatableContainers,org.springframework.core.annotation.TypeMappedAnnotation,org.apache.commons.logging.LogAdapter$Slf4jLocationAwareLog,org.springframework.context.index.CandidateComponentsIndexLoader,org.springframework.core.annotation.AnnotationsScanner,org.springframework.core.annotation.AnnotationTypeMapping,org.springframework.util.ConcurrentReferenceHashMap
                                        --trace-object-instantiation=ch.qos.logback.core.AsyncAppenderBase$Worker
                                        --initialize-at-build-time=org.slf4j.LoggerFactory,ch.qos.logback,org.springframework.core.annotation.AnnotationUtils,org.springframework.util.PropertyPlaceholderHelper,org.springframework.util.ClassUtils,org.springframework.core.annotation.PackagesAnnotationFilter,org.springframework.core.annotation.AnnotationTypeMappings,org.springframework.core.annotation.AnnotationFilter$1,org.springframework.core.annotation.AnnotationFilter$2,org.springframework.core.NativeDetector,org.springframework.core.annotation.MergedAnnotations$Search,org.springframework.core.io.support.PathMatchingResourcePatternResolver,org.springframework.core.SpringProperties,org.springframework.core.annotation.AttributeMethods,org.springframework.core.annotation.AnnotationFilter,org.springframework.util.AntPathMatcher,org.apache.commons.logging.LogAdapter,org.springframework.core.annotation.TypeMappedAnnotations,org.springframework.util.ReflectionUtils,org.springframework.util.AntPathMatcher$AntPathStringMatcher,org.springframework.core.annotation.RepeatableContainers$StandardRepeatableContainers,org.springframework.core.annotation.TypeMappedAnnotation,org.apache.commons.logging.LogAdapter$Slf4jLocationAwareLog,org.springframework.context.index.CandidateComponentsIndexLoader,org.springframework.core.annotation.AnnotationsScanner,org.springframework.core.annotation.AnnotationTypeMapping,org.springframework.util.ConcurrentReferenceHashMap,org.springframework.beans.BeanUtils,org.springframework.context.annotation.ConfigurationClassUtils,org.springframework.core.KotlinDetector,org.springframework.core.annotation.MergedAnnotationCollectors
                                        --allow-incomplete-classpath
                                        -H:+ReportExceptionStackTraces
                                        -H:+StaticExecutableWithDynamicLibC
                                        --features=cn.yimakeji.common.config.RuntimeRegistrationFeature
                                    </BP_NATIVE_IMAGE_BUILD_ARGUMENTS>
                                </env>
                            </image>

                            <mainClass>${start.class}</mainClass>
                            <!--                            <excludeDevtools>true</excludeDevtools>-->
                            <addResources>true</addResources>
                            <compilerArguments>-parameters</compilerArguments>
<!--                            <jvmArguments></jvmArguments>-->
                            <additionalProperties>
                                <encoding.source>${project.build.sourceEncoding}</encoding.source>
                                <encoding.reporting>${project.build.sourceEncoding}</encoding.reporting>
                                <java.source>${maven.compiler.source}</java.source>
                                <java.target>${maven.compiler.target}</java.target>
                            </additionalProperties>
                        </configuration>
                        <executions>
                            <execution>
                                <id>process-aot</id>
                                <goals>
                                    <goal>process-aot</goal>
                                </goals>
                            </execution>
                            <execution>
                                <goals>
                                    <goal>repackage</goal>
                                </goals>
                            </execution>
                        </executions>
                    </plugin>
                    <plugin>
                        <groupId>org.graalvm.buildtools</groupId>
                        <artifactId>native-maven-plugin</artifactId>
                        <version>${native-build-tools-plugin.version}</version>
                        <configuration>

                            <useArgFile>true</useArgFile>
                            <skip>false</skip>
                            <!--                            如果要启用调试信息的生成,请在插件配置中提供以下内容:-->
                            <debug>true</debug>
                            <!--启用详细输出-->
                            <verbose>true</verbose>
                            <mainClass>${start.class}</mainClass>
                            <buildArgs>
                                <buildArgs combine.children="append">
                                    <buildArg>-H:+AddAllCharsets</buildArg>
                                    <buildArg>-Djavax.xml.accessExternalDTD=all</buildArg>
                                </buildArgs>
                            </buildArgs>
                            <classesDirectory>${project.build.outputDirectory}</classesDirectory>
                            <!--                            <classesDirectory>${project.build.outputDirectory}</classesDirectory>-->
                            <metadataRepository>
                                <enabled>true</enabled>
                            </metadataRepository>
                            <requiredVersion>22.3</requiredVersion>
                        </configuration>
                        <executions>
                            <execution>
                                <id>add-reachability-metadata</id>
                                <goals>
                                    <goal>add-reachability-metadata</goal>
                                </goals>
                            </execution>
                        </executions>
                    </plugin>
                </plugins>

@mailbyms
Copy link

该Pull Request关联的Issue

#5527 (comment)

修改描述

增加对 lambda 表达式的支持

1.在使用了lambda 的类上增加注解 @GraalReflectionAotHints 2.增加graal Feature


package com.maishi.common.config;

import com.baomidou.mybatisplus.extension.aot.AotUtils;
import org.graalvm.nativeimage.hosted.Feature;
import org.graalvm.nativeimage.hosted.RuntimeSerialization;

import java.util.List;

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


    @Override
    public void duringSetup(DuringSetupAccess access) {
        //RuntimeSerialization.registerLambdaCapturingClass(AppAlarmLevelSubscribeController.class);

        //参数是父包, 会扫描有写 @GraalReflectionAotHints 的类
        List<Class<?>> graalAotHints = AotUtils.getGraalAotHints(List.of("com.maishi"));

        graalAotHints.forEach(RuntimeSerialization::registerLambdaCapturingClass);

    }
}

3.在pom.xml 文件增加 Feature,灵魂是这一句 --features=com.maishi.common.config.LambdaRegistrationFeature

<plugin>
                <groupId>org.graalvm.buildtools</groupId>
                <artifactId>native-maven-plugin</artifactId>
                <configuration>
                    <buildArgs combine.children="append">
                        <!--<buildArg>-enable-url-protocols=http</buildArg>-->
                        <buildArg>-H:+AddAllCharsets</buildArg>
                        <buildArg>--features=com.maishi.common.config.LambdaRegistrationFeature</buildArg>
                    </buildArgs>
                </configuration>
            </plugin>

其他就不说了.该咋样就咋样

非常棒,问题解决

@nieqiurong nieqiurong closed this Dec 20, 2023
@CV-Devlau
Copy link

CV-Devlau commented Mar 5, 2024

我也遇到了lambda表达式支持问题,感谢@z744489075提供思路,我优化了一下直接改成了不要注解形式的扫描,然后注册进去

import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.core.toolkit.support.SerializedLambda;
import com.baomidou.mybatisplus.extension.service.IService;
import org.graalvm.nativeimage.hosted.Feature;
import org.graalvm.nativeimage.hosted.RuntimeSerialization;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.type.filter.AssignableTypeFilter;
import org.springframework.core.type.filter.TypeFilter;
import org.springframework.util.ClassUtils;

import java.util.ArrayList;
import java.util.List;
/**
 * 用于注册graalvm lambda序列化的类
 *
 * 感谢z744489075提供的思路:https://github.com/baomidou/mybatis-plus/pull/5594
 * @author  yun.can
 * @since  2023/09/15
 */
public class RuntimeRegistrationFeature implements Feature {
	/**
	 * 找到某个包下面指定的父类的所有子类
	 * @param packageName 包名
	 * @param superClass 父类
	 * @return 子类集合
	 */
	public static List<Class<?>> findClasses(String packageName, Class<?> superClass) {
		ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
		TypeFilter filter = new AssignableTypeFilter(superClass);

		scanner.addIncludeFilter(filter);

		List<Class<?>> classes = new ArrayList<>();
		String basePackage = ClassUtils.convertClassNameToResourcePath(packageName);
		for (BeanDefinition candidate : scanner.findCandidateComponents(basePackage)) {
			try {
				Class<?> clazz = Class.forName(candidate.getBeanClassName());
				classes.add(clazz);
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
				// 处理异常
			}
		}

		return classes;
	}

	@Override
	public void duringSetup(Feature.DuringSetupAccess access) {
//		扫描指定包下IService的字类(实现类),然后全部注册到graalvm lamda 序列化中
		RuntimeRegistrationFeature.findClasses("cn.yimakeji", IService.class)
			.forEach(RuntimeSerialization::registerLambdaCapturingClass);
		RuntimeSerialization.register(SerializedLambda.class, SFunction.class);
	}
}

我目前已经用在我项目中了,非常棒

参数忘记给了,需要在native-image编译时添加spring相关类的参数,否则会造成编译失败

--initialize-at-build-time=org.slf4j.LoggerFactory,ch.qos.logback,org.springframework.core.annotation.AnnotationUtils,org.springframework.util.PropertyPlaceholderHelper,org.springframework.util.ClassUtils,org.springframework.core.annotation.PackagesAnnotationFilter,org.springframework.core.annotation.AnnotationTypeMappings,org.springframework.core.annotation.AnnotationFilter$1,org.springframework.core.annotation.AnnotationFilter$2,org.springframework.core.NativeDetector,org.springframework.core.annotation.MergedAnnotations$Search,org.springframework.core.io.support.PathMatchingResourcePatternResolver,org.springframework.core.SpringProperties,org.springframework.core.annotation.AttributeMethods,org.springframework.core.annotation.AnnotationFilter,org.springframework.util.AntPathMatcher,org.apache.commons.logging.LogAdapter,org.springframework.core.annotation.TypeMappedAnnotations,org.springframework.util.ReflectionUtils,org.springframework.util.AntPathMatcher$AntPathStringMatcher,org.springframework.core.annotation.RepeatableContainers$StandardRepeatableContainers,org.springframework.core.annotation.TypeMappedAnnotation,org.apache.commons.logging.LogAdapter$Slf4jLocationAwareLog,org.springframework.context.index.CandidateComponentsIndexLoader,org.springframework.core.annotation.AnnotationsScanner,org.springframework.core.annotation.AnnotationTypeMapping,org.springframework.util.ConcurrentReferenceHashMap,org.springframework.beans.BeanUtils,org.springframework.context.annotation.ConfigurationClassUtils,org.springframework.core.KotlinDetector,org.springframework.core.annotation.MergedAnnotationCollectors

以下这个是我完整配置

<plugins>
                    <plugin>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-maven-plugin</artifactId>
                        <extensions>true</extensions>
                        <configuration>
                            <profiles>
                                <profile>native</profile>
                            </profiles>
                            <!--                            <generatedResources>${project.build.directory}</generatedResources>-->
                            <!--                            <classifier>${repackage.classifier}</classifier>-->
                            <image>
                                <builder>paketobuildpacks/builder:tiny</builder>
                                <!--                                <builder>gcr.io/paketo-buildpacks/native-image</builder>-->
                                <!--docker-image配置:https://github.com/paketo-buildpacks/spring-boot-->
                                <env>
                                    <BP_NATIVE_IMAGE>true</BP_NATIVE_IMAGE>
                                    <!--配置代理-->
                                    <HTTP_PROXY>http://192.168.1.49:7890</HTTP_PROXY>
                                    <HTTPS_PROXY>http://192.168.1.49:7890</HTTPS_PROXY>
                                    <BP_JVM_VERSION>${java.version}</BP_JVM_VERSION>
                                    <!--                                    <BP_BINARY_COMPRESSION_METHOD>upx</BP_BINARY_COMPRESSION_METHOD>-->
                                    <BP_NATIVE_IMAGE_BUILD_ARGUMENTS>
                                        --verbose
                                        --enable-https
                                        --enable-http
                                        --initialize-at-build-time=sun.instrument.InstrumentationImpl
                                        --add-opens=java.base/java.nio=ALL-UNNAMED
                                        --add-opens=java.base/java.lang=ALL-UNNAMED
                                        --add-opens=java.base/java.text=ALL-UNNAMED
                                        --add-opens=java.base/java.net=ALL-UNNAMED
                                        --add-opens=java.base/java.util.concurrent=ALL-UNNAMED
                                        --add-opens=java.base/java.io=ALL-UNNAMED
                                        --add-opens=java.base/java.util=ALL-UNNAMED
                                        --add-opens=java.base/java.math=ALL-UNNAMED
                                        --add-opens=java.base/jdk.internal.misc=ALL-UNNAMED
                                        --add-opens=java.base/jdk.internal.ref=ALL-UNNAMED
                                        --trace-class-initialization=ch.qos.logback.classic.Logger,org.springframework.core.annotation.AnnotationUtils,org.springframework.util.PropertyPlaceholderHelper,org.springframework.util.ClassUtils,org.springframework.core.annotation.PackagesAnnotationFilter,org.springframework.core.annotation.AnnotationTypeMappings,org.springframework.core.annotation.AnnotationFilter$1,org.springframework.core.annotation.AnnotationFilter$2,org.springframework.core.NativeDetector,org.springframework.core.annotation.MergedAnnotations$Search,org.springframework.core.io.support.PathMatchingResourcePatternResolver,org.springframework.core.SpringProperties,org.springframework.core.annotation.AttributeMethods,org.springframework.core.annotation.AnnotationFilter,org.springframework.util.AntPathMatcher,org.apache.commons.logging.LogAdapter,org.springframework.core.annotation.TypeMappedAnnotations,org.springframework.util.ReflectionUtils,org.springframework.util.AntPathMatcher$AntPathStringMatcher,org.springframework.core.annotation.RepeatableContainers$StandardRepeatableContainers,org.springframework.core.annotation.TypeMappedAnnotation,org.apache.commons.logging.LogAdapter$Slf4jLocationAwareLog,org.springframework.context.index.CandidateComponentsIndexLoader,org.springframework.core.annotation.AnnotationsScanner,org.springframework.core.annotation.AnnotationTypeMapping,org.springframework.util.ConcurrentReferenceHashMap
                                        --trace-object-instantiation=ch.qos.logback.core.AsyncAppenderBase$Worker
                                        --initialize-at-build-time=org.slf4j.LoggerFactory,ch.qos.logback,org.springframework.core.annotation.AnnotationUtils,org.springframework.util.PropertyPlaceholderHelper,org.springframework.util.ClassUtils,org.springframework.core.annotation.PackagesAnnotationFilter,org.springframework.core.annotation.AnnotationTypeMappings,org.springframework.core.annotation.AnnotationFilter$1,org.springframework.core.annotation.AnnotationFilter$2,org.springframework.core.NativeDetector,org.springframework.core.annotation.MergedAnnotations$Search,org.springframework.core.io.support.PathMatchingResourcePatternResolver,org.springframework.core.SpringProperties,org.springframework.core.annotation.AttributeMethods,org.springframework.core.annotation.AnnotationFilter,org.springframework.util.AntPathMatcher,org.apache.commons.logging.LogAdapter,org.springframework.core.annotation.TypeMappedAnnotations,org.springframework.util.ReflectionUtils,org.springframework.util.AntPathMatcher$AntPathStringMatcher,org.springframework.core.annotation.RepeatableContainers$StandardRepeatableContainers,org.springframework.core.annotation.TypeMappedAnnotation,org.apache.commons.logging.LogAdapter$Slf4jLocationAwareLog,org.springframework.context.index.CandidateComponentsIndexLoader,org.springframework.core.annotation.AnnotationsScanner,org.springframework.core.annotation.AnnotationTypeMapping,org.springframework.util.ConcurrentReferenceHashMap,org.springframework.beans.BeanUtils,org.springframework.context.annotation.ConfigurationClassUtils,org.springframework.core.KotlinDetector,org.springframework.core.annotation.MergedAnnotationCollectors
                                        --allow-incomplete-classpath
                                        -H:+ReportExceptionStackTraces
                                        -H:+StaticExecutableWithDynamicLibC
                                        --features=cn.yimakeji.common.config.RuntimeRegistrationFeature
                                    </BP_NATIVE_IMAGE_BUILD_ARGUMENTS>
                                </env>
                            </image>

                            <mainClass>${start.class}</mainClass>
                            <!--                            <excludeDevtools>true</excludeDevtools>-->
                            <addResources>true</addResources>
                            <compilerArguments>-parameters</compilerArguments>
<!--                            <jvmArguments></jvmArguments>-->
                            <additionalProperties>
                                <encoding.source>${project.build.sourceEncoding}</encoding.source>
                                <encoding.reporting>${project.build.sourceEncoding}</encoding.reporting>
                                <java.source>${maven.compiler.source}</java.source>
                                <java.target>${maven.compiler.target}</java.target>
                            </additionalProperties>
                        </configuration>
                        <executions>
                            <execution>
                                <id>process-aot</id>
                                <goals>
                                    <goal>process-aot</goal>
                                </goals>
                            </execution>
                            <execution>
                                <goals>
                                    <goal>repackage</goal>
                                </goals>
                            </execution>
                        </executions>
                    </plugin>
                    <plugin>
                        <groupId>org.graalvm.buildtools</groupId>
                        <artifactId>native-maven-plugin</artifactId>
                        <version>${native-build-tools-plugin.version}</version>
                        <configuration>

                            <useArgFile>true</useArgFile>
                            <skip>false</skip>
                            <!--                            如果要启用调试信息的生成,请在插件配置中提供以下内容:-->
                            <debug>true</debug>
                            <!--启用详细输出-->
                            <verbose>true</verbose>
                            <mainClass>${start.class}</mainClass>
                            <buildArgs>
                                <buildArgs combine.children="append">
                                    <buildArg>-H:+AddAllCharsets</buildArg>
                                    <buildArg>-Djavax.xml.accessExternalDTD=all</buildArg>
                                </buildArgs>
                            </buildArgs>
                            <classesDirectory>${project.build.outputDirectory}</classesDirectory>
                            <!--                            <classesDirectory>${project.build.outputDirectory}</classesDirectory>-->
                            <metadataRepository>
                                <enabled>true</enabled>
                            </metadataRepository>
                            <requiredVersion>22.3</requiredVersion>
                        </configuration>
                        <executions>
                            <execution>
                                <id>add-reachability-metadata</id>
                                <goals>
                                    <goal>add-reachability-metadata</goal>
                                </goals>
                            </execution>
                        </executions>
                    </plugin>
                </plugins>

你好,我通过这种方式后打包,所有注册的类都提示我 SysUserServiceImpl was unintentionally initialized at build time

@yuanluochenfeng
Copy link

我也遇到了lambda表达式支持问题,感谢@z744489075提供思路,我优化了一下直接改成了不要注解形式的扫描,然后注册进去

import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.core.toolkit.support.SerializedLambda;
import com.baomidou.mybatisplus.extension.service.IService;
import org.graalvm.nativeimage.hosted.Feature;
import org.graalvm.nativeimage.hosted.RuntimeSerialization;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.type.filter.AssignableTypeFilter;
import org.springframework.core.type.filter.TypeFilter;
import org.springframework.util.ClassUtils;

import java.util.ArrayList;
import java.util.List;
/**
 * 用于注册graalvm lambda序列化的类
 *
 * 感谢z744489075提供的思路:https://github.com/baomidou/mybatis-plus/pull/5594
 * @author  yun.can
 * @since  2023/09/15
 */
public class RuntimeRegistrationFeature implements Feature {
	/**
	 * 找到某个包下面指定的父类的所有子类
	 * @param packageName 包名
	 * @param superClass 父类
	 * @return 子类集合
	 */
	public static List<Class<?>> findClasses(String packageName, Class<?> superClass) {
		ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
		TypeFilter filter = new AssignableTypeFilter(superClass);

		scanner.addIncludeFilter(filter);

		List<Class<?>> classes = new ArrayList<>();
		String basePackage = ClassUtils.convertClassNameToResourcePath(packageName);
		for (BeanDefinition candidate : scanner.findCandidateComponents(basePackage)) {
			try {
				Class<?> clazz = Class.forName(candidate.getBeanClassName());
				classes.add(clazz);
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
				// 处理异常
			}
		}

		return classes;
	}

	@Override
	public void duringSetup(Feature.DuringSetupAccess access) {
//		扫描指定包下IService的字类(实现类),然后全部注册到graalvm lamda 序列化中
		RuntimeRegistrationFeature.findClasses("cn.yimakeji", IService.class)
			.forEach(RuntimeSerialization::registerLambdaCapturingClass);
		RuntimeSerialization.register(SerializedLambda.class, SFunction.class);
	}
}

我目前已经用在我项目中了,非常棒

参数忘记给了,需要在native-image编译时添加spring相关类的参数,否则会造成编译失败

--initialize-at-build-time=org.slf4j.LoggerFactory,ch.qos.logback,org.springframework.core.annotation.AnnotationUtils,org.springframework.util.PropertyPlaceholderHelper,org.springframework.util.ClassUtils,org.springframework.core.annotation.PackagesAnnotationFilter,org.springframework.core.annotation.AnnotationTypeMappings,org.springframework.core.annotation.AnnotationFilter$1,org.springframework.core.annotation.AnnotationFilter$2,org.springframework.core.NativeDetector,org.springframework.core.annotation.MergedAnnotations$Search,org.springframework.core.io.support.PathMatchingResourcePatternResolver,org.springframework.core.SpringProperties,org.springframework.core.annotation.AttributeMethods,org.springframework.core.annotation.AnnotationFilter,org.springframework.util.AntPathMatcher,org.apache.commons.logging.LogAdapter,org.springframework.core.annotation.TypeMappedAnnotations,org.springframework.util.ReflectionUtils,org.springframework.util.AntPathMatcher$AntPathStringMatcher,org.springframework.core.annotation.RepeatableContainers$StandardRepeatableContainers,org.springframework.core.annotation.TypeMappedAnnotation,org.apache.commons.logging.LogAdapter$Slf4jLocationAwareLog,org.springframework.context.index.CandidateComponentsIndexLoader,org.springframework.core.annotation.AnnotationsScanner,org.springframework.core.annotation.AnnotationTypeMapping,org.springframework.util.ConcurrentReferenceHashMap,org.springframework.beans.BeanUtils,org.springframework.context.annotation.ConfigurationClassUtils,org.springframework.core.KotlinDetector,org.springframework.core.annotation.MergedAnnotationCollectors

以下这个是我完整配置

<plugins>
                    <plugin>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-maven-plugin</artifactId>
                        <extensions>true</extensions>
                        <configuration>
                            <profiles>
                                <profile>native</profile>
                            </profiles>
                            <!--                            <generatedResources>${project.build.directory}</generatedResources>-->
                            <!--                            <classifier>${repackage.classifier}</classifier>-->
                            <image>
                                <builder>paketobuildpacks/builder:tiny</builder>
                                <!--                                <builder>gcr.io/paketo-buildpacks/native-image</builder>-->
                                <!--docker-image配置:https://github.com/paketo-buildpacks/spring-boot-->
                                <env>
                                    <BP_NATIVE_IMAGE>true</BP_NATIVE_IMAGE>
                                    <!--配置代理-->
                                    <HTTP_PROXY>http://192.168.1.49:7890</HTTP_PROXY>
                                    <HTTPS_PROXY>http://192.168.1.49:7890</HTTPS_PROXY>
                                    <BP_JVM_VERSION>${java.version}</BP_JVM_VERSION>
                                    <!--                                    <BP_BINARY_COMPRESSION_METHOD>upx</BP_BINARY_COMPRESSION_METHOD>-->
                                    <BP_NATIVE_IMAGE_BUILD_ARGUMENTS>
                                        --verbose
                                        --enable-https
                                        --enable-http
                                        --initialize-at-build-time=sun.instrument.InstrumentationImpl
                                        --add-opens=java.base/java.nio=ALL-UNNAMED
                                        --add-opens=java.base/java.lang=ALL-UNNAMED
                                        --add-opens=java.base/java.text=ALL-UNNAMED
                                        --add-opens=java.base/java.net=ALL-UNNAMED
                                        --add-opens=java.base/java.util.concurrent=ALL-UNNAMED
                                        --add-opens=java.base/java.io=ALL-UNNAMED
                                        --add-opens=java.base/java.util=ALL-UNNAMED
                                        --add-opens=java.base/java.math=ALL-UNNAMED
                                        --add-opens=java.base/jdk.internal.misc=ALL-UNNAMED
                                        --add-opens=java.base/jdk.internal.ref=ALL-UNNAMED
                                        --trace-class-initialization=ch.qos.logback.classic.Logger,org.springframework.core.annotation.AnnotationUtils,org.springframework.util.PropertyPlaceholderHelper,org.springframework.util.ClassUtils,org.springframework.core.annotation.PackagesAnnotationFilter,org.springframework.core.annotation.AnnotationTypeMappings,org.springframework.core.annotation.AnnotationFilter$1,org.springframework.core.annotation.AnnotationFilter$2,org.springframework.core.NativeDetector,org.springframework.core.annotation.MergedAnnotations$Search,org.springframework.core.io.support.PathMatchingResourcePatternResolver,org.springframework.core.SpringProperties,org.springframework.core.annotation.AttributeMethods,org.springframework.core.annotation.AnnotationFilter,org.springframework.util.AntPathMatcher,org.apache.commons.logging.LogAdapter,org.springframework.core.annotation.TypeMappedAnnotations,org.springframework.util.ReflectionUtils,org.springframework.util.AntPathMatcher$AntPathStringMatcher,org.springframework.core.annotation.RepeatableContainers$StandardRepeatableContainers,org.springframework.core.annotation.TypeMappedAnnotation,org.apache.commons.logging.LogAdapter$Slf4jLocationAwareLog,org.springframework.context.index.CandidateComponentsIndexLoader,org.springframework.core.annotation.AnnotationsScanner,org.springframework.core.annotation.AnnotationTypeMapping,org.springframework.util.ConcurrentReferenceHashMap
                                        --trace-object-instantiation=ch.qos.logback.core.AsyncAppenderBase$Worker
                                        --initialize-at-build-time=org.slf4j.LoggerFactory,ch.qos.logback,org.springframework.core.annotation.AnnotationUtils,org.springframework.util.PropertyPlaceholderHelper,org.springframework.util.ClassUtils,org.springframework.core.annotation.PackagesAnnotationFilter,org.springframework.core.annotation.AnnotationTypeMappings,org.springframework.core.annotation.AnnotationFilter$1,org.springframework.core.annotation.AnnotationFilter$2,org.springframework.core.NativeDetector,org.springframework.core.annotation.MergedAnnotations$Search,org.springframework.core.io.support.PathMatchingResourcePatternResolver,org.springframework.core.SpringProperties,org.springframework.core.annotation.AttributeMethods,org.springframework.core.annotation.AnnotationFilter,org.springframework.util.AntPathMatcher,org.apache.commons.logging.LogAdapter,org.springframework.core.annotation.TypeMappedAnnotations,org.springframework.util.ReflectionUtils,org.springframework.util.AntPathMatcher$AntPathStringMatcher,org.springframework.core.annotation.RepeatableContainers$StandardRepeatableContainers,org.springframework.core.annotation.TypeMappedAnnotation,org.apache.commons.logging.LogAdapter$Slf4jLocationAwareLog,org.springframework.context.index.CandidateComponentsIndexLoader,org.springframework.core.annotation.AnnotationsScanner,org.springframework.core.annotation.AnnotationTypeMapping,org.springframework.util.ConcurrentReferenceHashMap,org.springframework.beans.BeanUtils,org.springframework.context.annotation.ConfigurationClassUtils,org.springframework.core.KotlinDetector,org.springframework.core.annotation.MergedAnnotationCollectors
                                        --allow-incomplete-classpath
                                        -H:+ReportExceptionStackTraces
                                        -H:+StaticExecutableWithDynamicLibC
                                        --features=cn.yimakeji.common.config.RuntimeRegistrationFeature
                                    </BP_NATIVE_IMAGE_BUILD_ARGUMENTS>
                                </env>
                            </image>

                            <mainClass>${start.class}</mainClass>
                            <!--                            <excludeDevtools>true</excludeDevtools>-->
                            <addResources>true</addResources>
                            <compilerArguments>-parameters</compilerArguments>
<!--                            <jvmArguments></jvmArguments>-->
                            <additionalProperties>
                                <encoding.source>${project.build.sourceEncoding}</encoding.source>
                                <encoding.reporting>${project.build.sourceEncoding}</encoding.reporting>
                                <java.source>${maven.compiler.source}</java.source>
                                <java.target>${maven.compiler.target}</java.target>
                            </additionalProperties>
                        </configuration>
                        <executions>
                            <execution>
                                <id>process-aot</id>
                                <goals>
                                    <goal>process-aot</goal>
                                </goals>
                            </execution>
                            <execution>
                                <goals>
                                    <goal>repackage</goal>
                                </goals>
                            </execution>
                        </executions>
                    </plugin>
                    <plugin>
                        <groupId>org.graalvm.buildtools</groupId>
                        <artifactId>native-maven-plugin</artifactId>
                        <version>${native-build-tools-plugin.version}</version>
                        <configuration>

                            <useArgFile>true</useArgFile>
                            <skip>false</skip>
                            <!--                            如果要启用调试信息的生成,请在插件配置中提供以下内容:-->
                            <debug>true</debug>
                            <!--启用详细输出-->
                            <verbose>true</verbose>
                            <mainClass>${start.class}</mainClass>
                            <buildArgs>
                                <buildArgs combine.children="append">
                                    <buildArg>-H:+AddAllCharsets</buildArg>
                                    <buildArg>-Djavax.xml.accessExternalDTD=all</buildArg>
                                </buildArgs>
                            </buildArgs>
                            <classesDirectory>${project.build.outputDirectory}</classesDirectory>
                            <!--                            <classesDirectory>${project.build.outputDirectory}</classesDirectory>-->
                            <metadataRepository>
                                <enabled>true</enabled>
                            </metadataRepository>
                            <requiredVersion>22.3</requiredVersion>
                        </configuration>
                        <executions>
                            <execution>
                                <id>add-reachability-metadata</id>
                                <goals>
                                    <goal>add-reachability-metadata</goal>
                                </goals>
                            </execution>
                        </executions>
                    </plugin>
                </plugins>

你好,我通过这种方式后打包,所有注册的类都提示我 SysUserServiceImpl was unintentionally initialized at build time

试下在buildArgs标签下增加--initialize-at-build-time=xx.xx.xx.SysUserServiceImpl(完全限定名),将涉及到的类都加上

@CV-Devlau
Copy link

CV-Devlau commented Mar 7, 2024

试下在buildArgs标签下增加--initialize-at-build-time=xx.xx.xx.SysUserServiceImpl(完全限定名),将涉及到的类都加上

感谢,因为我同时扫描了 service和 mapper类较多,我猜测Spring提供的扫描类可能中间某些因为某些注解或操作无意初始化了类,所以我尝试使用其他扫描工具类解决了这个问题

package org.dromara.feature;

import cn.hutool.core.util.ClassUtil;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.core.toolkit.support.SerializedLambda;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
import org.graalvm.nativeimage.hosted.Feature;
import org.graalvm.nativeimage.hosted.RuntimeSerialization;
import org.springframework.stereotype.Service;

import java.util.HashSet;
import java.util.Set;

/**
 * 用于注册graalvm lambda序列化的类
 *
 * 感谢z744489075提供的思路:https://github.com/baomidou/mybatis-plus/pull/5594
 * @author  devlau
 * @since  2024/3/6
 */

public class LambdaRegistrationFeature implements Feature {
	/**
	 * 找到某个包下面指定的父类的所有子类
	 * @return 子类集合
	 */
	public static Set<Class<?>> findClasses() {
		Set<Class<?>> serviceClass = ClassUtil.scanPackageByAnnotation("org.dromara", Service.class);
		Set<Class<?>> mapperClass = ClassUtil.scanPackageBySuper("org.dromara", BaseMapperPlus.class);
		HashSet<Class<?>> classes = new HashSet<>(serviceClass);
		classes.addAll(mapperClass);
		return classes;
	}

	@Override
	public void duringSetup(Feature.DuringSetupAccess access) {
//		扫描指定包下IService的字类(实现类),然后全部注册到graalvm lamda 序列化中
		Set<Class<?>> classes = LambdaRegistrationFeature.findClasses();
		for (Class<?> aClass : classes) {
			RuntimeSerialization.registerLambdaCapturingClass(aClass);
		}
		RuntimeSerialization.register(SerializedLambda.class, SFunction.class);
	}
}

同时需要在buildArgs标签下增加

--initialize-at-build-time=cn.hutool.core.util.ClassLoaderUtil
--initialize-at-build-time=cn.hutool.core.convert.BasicType
--initialize-at-build-time=cn.hutool.core.util.CharsetUtil
--features=org.dromara.feature.LambdaRegistrationFeature

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants