放弃
作者:Chiu2024-03-23 22:10:48阅读数:141

白干一星期

这段时间工作压力可以说相当的重,和我一起做项目的同事把大量体力性、逻辑复杂的劳动都给了我,做得慢还会挨他的骂(实际上对于一个工作半年的人效率已经不错了),我目前就处于一个心态低迷的时期。不过我的心倒不沉迷在这边。我还是希望能在项目上用上GraalVM最新的编译技术,使用Native镜像运行这个项目。使用Spring的插件编译成Mac OS下的可执行文件并不是问题,问题在于Docker的架构上。

本来镜像构建已经顺利完成,让我很兴奋:

但是,一看架构我就傻眼了,竟然是ARM64的。

Docker本身是虚拟出的一个执行环境,本质都是Linux。这时候CPU架构就显得非常微妙了。我是用的编译机器是一台m1的mac,ARM结构,所以使用spring boot官方插件编译出的也是arm64的docker镜像。我去stackoverflow等网站查了很久,没找到可以调节编译指令集的参数。关键在于这个镜像是好的还是坏的也没法验证,因为这镜像在我的机器上根本启动不了,是非常尴尬的。

我也尝试了使用docker buildx这类工具,但是实际上并不能用。想了下还是不继续搞这个东西了。

不过这其中我也了解了aot的一些其他好处。比如开启spring.aot.enabled=true可以一定程度提升应用启动速度,但是总归还是不如直接native启动。目前这个项目在我的电脑上启动只需要一秒:

另外,编译完以后可能存在反射找不到类的情况,需要手动注册:

java 复制代码
package org.chiu.megalith.infra.config;

import lombok.SneakyThrows;
import org.chiu.megalith.blog.dto.BLogEntityDto;
import org.chiu.megalith.infra.listener.CacheMessageListener;
import org.chiu.megalith.infra.valid.ListValueConstraintValidator;
import org.chiu.megalith.infra.valid.PhoneConstraintValidator;
import org.chiu.megalith.infra.valid.UsernameConstraintValidator;
import org.chiu.megalith.security.role.DefaultRoleHolder;
import org.chiu.megalith.security.role.HighestRoleHolder;
import org.chiu.megalith.security.vo.LoginSuccessVo;
import org.chiu.megalith.security.vo.UserInfoVo;
import org.springframework.aot.hint.ExecutableMode;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.util.ReflectionUtils;

import java.util.LinkedHashSet;
import java.util.Set;

public class CustomRuntimeHints implements RuntimeHintsRegistrar {
    @SneakyThrows
    @Override// Register method for reflection
    public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
        // Register method for reflection
        hints.reflection().registerMethod(ReflectionUtils.findMethod(CacheMessageListener.class, "handleMessage", Set.class), ExecutableMode.INVOKE);
        hints.reflection().registerMethod(ReflectionUtils.findMethod(HighestRoleHolder.class, "getRole"), ExecutableMode.INVOKE);
        hints.reflection().registerMethod(ReflectionUtils.findMethod(DefaultRoleHolder.class, "getRole"), ExecutableMode.INVOKE);

        hints.reflection().registerConstructor(LinkedHashSet.class.getDeclaredConstructor(), ExecutableMode.INVOKE);
        hints.reflection().registerConstructor(ListValueConstraintValidator.class.getDeclaredConstructor(), ExecutableMode.INVOKE);
        hints.reflection().registerConstructor(PhoneConstraintValidator.class.getDeclaredConstructor(), ExecutableMode.INVOKE);
        hints.reflection().registerConstructor(UsernameConstraintValidator.class.getDeclaredConstructor(), ExecutableMode.INVOKE);

        hints.serialization().registerType(LoginSuccessVo.class);
        hints.serialization().registerType(UserInfoVo.class);
        hints.serialization().registerType(BLogEntityDto.class);

        // Register resources
        hints.resources().registerPattern("ValidationMessages.properties");
    }
}

然后

java 复制代码
package org.chiu.megalith;

import org.chiu.megalith.infra.config.CustomRuntimeHints;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ImportRuntimeHints;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;


@SpringBootApplication(proxyBeanMethods = false)
@EnableAsync
@EnableScheduling
@EnableMethodSecurity
@ImportRuntimeHints({ CustomRuntimeHints.class })
public class MegalithApplication {

	public static void main(String[] args) {
		SpringApplication.run(MegalithApplication.class, args);
	}

}

从这里可以看出Spring是不会帮你分析代码结构的,除了部门bean的出入参框架会帮你手动处理,其他用到反射的方法、序列化的方法都需要手动标记,这点迁移起来是不那么平滑的。