同样一套代码,基于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
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]
最初怀疑过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本质也是获取到当前启动类,然后再通过上面的扫描注解扫描其他包,来自动注入。
所以原因很显而易见了。
/**
* 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是\斜杠,或者就是单纯路径有错误,需要判断是那个系统,分别取不同的路径