Linux和windows编译打包springboot项目区别

问题遇到的现象和发生背景

同样一套代码,基于springboot2.3.12开发,在linux和windows系统上使用相同版本的JDK和maven编译打包,放在linux机器上启动,windows系统打包的jar能正常启动,linux系统打包的jar启动报错,错误描述是bean找不到。两个jar包的大小不一致,但差距不大,Linux打包的jar大小为117135618字节,windows系统打包的jar大小为117135630字节。通过jar包比较工具比较两个包没有发现区别,提问:Linux系统和windows系统编译打包过程有什么区别?

遇到的现象和发生背景,请写出第一个错误信息

java.lang.NullPointerException: null

org.springframework.beans.factory.BeanCreationException

用代码块功能插入代码,请勿粘贴截图。 不用代码块回答率下降 50%

linux编译打包的代码启动时报错,通过以下形式的代码获取不到bean

public class SpringUtil implements ApplicationContextAware{ ...}

Map<String, Object> beans = SpringUtil.getApplicationContext().getBeansWithAnnotation(Mapper.class);
运行结果及详细报错内容

at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:160) ~[spring-beans-5.2.15.RELEASE.jar!/:5.2.15.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:415) ~[spring-beans-5.2.15.RELEASE.jar!/:5.2.15.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1791) ~[spring-beans-5.2.15.RELEASE.jar!/:5.2.15.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:594) ~[spring-beans-5.2.15.RELEASE.jar!/:5.2.15.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:516) ~[spring-beans-5.2.15.RELEASE.jar!/:5.2.15.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:324) ~[spring-beans-5.2.15.RELEASE.jar!/:5.2.15.RELEASE]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.2.15.RELEASE.jar!/:5.2.15.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:322) ~[spring-beans-5.2.15.RELEASE.jar!/:5.2.15.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-5.2.15.RELEASE.jar!/:5.2.15.RELEASE]

我的解答思路和尝试过的方法,不写自己思路的,回答率下降 60%

最初怀疑过windows和Linux上安装的JDK,maven版本不一致,后来尝试统一版本问题仍然没有解决。
后来怀疑git克隆到linux和windows的代码不一致,后来统一使用一套源代码分别放在linux和windows编译打包,问题仍然没有解决。
再者怀疑linux系统编译打包时和windows编码不同或者类加载顺序不同,由于缺乏相关的知识和经验,目前没办法求证。
请大家回答我的疑惑或者提供解决问题的思路,谢谢!

你好,启动过程涉及到虚拟机,排查一:看看JDK版本,JDK8和更高版本启动后,以及跨平台都有影响。
比如自定义注解的扫描,需要获取堆栈信息判断下
提供代码

    public static String getStackTrace() {
        StackTraceElement[] stack = new Throwable().getStackTrace();
        Stack<StackTraceElement> newStack = new Stack<>();
        for (int index = 0; index < stack.length; index++) {
            if (!stack[index].getClassName().startsWith("java.lang.reflect") &&
                    !stack[index].getClassName().startsWith("sun.reflect") &&
                    !stack[index].getClassName().startsWith("org.springframework.boot") &&
                    !stack[index].getClassName().startsWith("jdk.internal.reflect"))
            {
                newStack.push(stack[index]);
            }
            log.trace("stack info: {}", stack[index]);
        }
        // Jar 启动会 出现 注解扫描失败
        //return stack[stack.length - 1].getClassName();
        return newStack.pop().getClassName();
    }

两种结果,看完下面后你应该就意识到,SpringBoot在扫描注解的原理,其实是需要先启动成功,而启动失败大多情况下从底层上可以看到就是JDK版本的原因。
启动失败导致Bean无法注入,或者是容器没有实例化都是有可能,因为在项目里,SpringBoot本质也是获取到当前启动类,然后再通过上面的扫描注解扫描其他包,来自动注入。
所以原因很显而易见了。

  • 容器没有启动成功,通过堆栈信息来启动没找到,JDK版本问题
  • Bean没有注入,Maven依赖不到?注解没有发现,同名注解导致失败错误,没有注解
 /**
     * fix: 修复 Jar 包启动,注解扫描失败的问题
     * 这里如果使用 springboot 启动的话,有两种启动情况
     * 1. 项目启动方式:那么堆栈信息最后堆栈类为 启动类,本项目堆栈信息
     * stack info: cn.fyupeng.util.ReflectUtil.getStackTrace(ReflectUtil.java:31)
     * stack info: cn.fyupeng.net.AbstractRpcServer.scanServices(AbstractRpcServer.java:36)
     * stack info: cn.fyupeng.net.netty.server.NettyServer.<init>(NettyServer.java:46)
     * stack info: cn.fyupeng.UserServer.run(UserServer.java:42)
     * stack info: org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:813)
     * stack info: org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:797)
     * stack info: org.springframework.boot.SpringApplication.run(SpringApplication.java:324)
     * stack info: org.springframework.boot.SpringApplication.run(SpringApplication.java:1260)
     * stack info: org.springframework.boot.SpringApplication.run(SpringApplication.java:1248)
     * stack info: cn.fyupeng.UserServer.main(UserServer.java:35)
     *
     * 2. Jar启动方式:是先按照第一种方式启动,然后本地方法反射,最后还是在 springboot 的 JarLauncher 启动器上启动
     * stack info: cn.fyupeng.util.ReflectUtil.getStackTrace(ReflectUtil.java:31)
     * stack info: cn.fyupeng.net.AbstractRpcServer.scanServices(AbstractRpcServer.java:36)
     * stack info: cn.fyupeng.net.netty.server.NettyServer.<init>(NettyServer.java:46)
     * stack info: .UserServer.run(UserServer.java:42)
     * stack info: org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:813)
     * stack info: org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:797)
     * stack info: org.springframework.boot.SpringApplication.run(SpringApplication.java:324)
     * stack info: org.springframework.boot.SpringApplication.run(SpringApplication.java:1260)
     * stack info: org.springframework.boot.SpringApplication.run(SpringApplication.java:1248)
     * stack info: cn.fyupeng.UserServer.main(UserServer.java:35)
     * stack info: sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
     * stack info: sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
     * stack info: sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
     * stack info: java.lang.reflect.Method.invoke(Method.java:498)
     * stack info: org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:48)
     * stack info: org.springframework.boot.loader.Launcher.launch(Launcher.java:87)
     * stack info: org.springframework.boot.loader.Launcher.launch(Launcher.java:50)
     * stack info: org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:51)
     *
     * @return
     */

如果真如我所言,跨平台或者JDK版本过高,推荐你把JDK降到8试试
如仍有问题继续反馈。

应该工程内指定文件目录有错误,例如linux是/,windows是\斜杠,或者就是单纯路径有错误,需要判断是那个系统,分别取不同的路径