问题描述

最近运维在部署应用的时候偶尔会碰到下面的异常:

Exception in thread "main" java.lang.NoClassDefFoundError: org.springframework.beans.FatalBeanException
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:547)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:304)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:300)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:195)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:700)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:760)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:93)
at com.alibaba.dubbo.container.spring.SpringContainer.start(SpringContainer.java:50)
at com.alibaba.dubbo.container.Main.main(Main.java:80)

这个异常看上去是org.springframework.beans.FatalBeanException在运行时找不到class,但是调试起来很懵逼。

问题分析

尝试一

怀疑这个类org.springframework.beans.FatalBeanExceptionclassloader的时候无法找到。

这个类org.springframework.beans.FatalBeanExceptionspring-beans包下,查看打包的lib下存在spring-beans包,查看运行jar中的META-INF下的MANIFEST.MF文件中也有lib/spring-beans-4.0.0.RELEASE.jar

因此排除了这个怀疑。

ps.这里要区分一下NoClassDefFoundErrorClassNotFoundException异常看这篇文章

尝试二

这个类在spring-beans包中,那是不是这个jar包损坏无法读取?

查看了jar包信息以及打开与解压也排除了jar包损坏的可能性。

尝试三

修改log级别改为debug看会不会有更多的日志输出。

通过日志级别的调整为debug后,除了都了一些debug的常规日志以外,错误相关的日志还是跟上面的输出一样,因此也是无济于事。

尝试四

通过arthas观察org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory这个类的doCreateBean这个方法异常的输出。

arthas ${pid}

watch org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory doCreateBean "{params, throwExp}" -e -x 2

发现如下更多的日志:

ts=2018-09-25 18:06:37;result=@ArrayList[
@Object[][
@String[xxxMapper],
@RootBeanDefinition[Root bean: class [org.mybatis.spring.mapper.MapperFa
ctoryBean]; scope=singleton; abstract=false; lazyInit=false; autowireMode=2; dep
endencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; fac
toryMethodName=null; initMethodName=null; destroyMethodName=null; defined in URL
[jar:file:/E:/user/desktop/ningyu/Desktop/xxx-main-1.0.0-SNAPSHOT-201809251509/
lib/xxx-service-JD-1.0.0-SNAPSHOT.jar!/com/xxx/xxx/order/mapper/xxxMapper.class]],
null,
],
java.lang.NoClassDefFoundError: org.springframework.beans.FatalBeanException
at org.springframework.beans.factory.support.AbstractAutowireCapableBean
Factory.doCreateBean(AbstractAutowireCapableBeanFactory.java:547)
at org.springframework.beans.factory.support.AbstractAutowireCapableBean
Factory.createBean(AbstractAutowireCapableBeanFactory.java:475)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getOb
ject(AbstractBeanFactory.java:304)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistr
y.getSingleton(DefaultSingletonBeanRegistry.java:228)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBe
an(AbstractBeanFactory.java:300)
at org.springframework.beans.factory.support.AbstractBeanFactory.getType
ForFactoryBean(AbstractBeanFactory.java:1420)
at org.springframework.beans.factory.support.AbstractAutowireCapableBean
Factory.getTypeForFactoryBean(AbstractAutowireCapableBeanFactory.java:788)
at org.springframework.beans.factory.support.AbstractBeanFactory.isTypeM
atch(AbstractBeanFactory.java:543)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.
doGetBeanNamesForType(DefaultListableBeanFactory.java:384)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.
getBeanNamesForType(DefaultListableBeanFactory.java:361)
at org.springframework.beans.factory.BeanFactoryUtils.beanNamesForTypeIn
cludingAncestors(BeanFactoryUtils.java:187)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.
findAutowireCandidates(DefaultListableBeanFactory.java:999)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.
doResolveDependency(DefaultListableBeanFactory.java:957)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.
resolveDependency(DefaultListableBeanFactory.java:855)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanP
ostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.j
ava:480)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject
(InjectionMetadata.java:87)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanP
ostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java
:289)
at org.springframework.beans.factory.support.AbstractAutowireCapableBean
Factory.populateBean(AbstractAutowireCapableBeanFactory.java:1185)
at org.springframework.beans.factory.support.AbstractAutowireCapableBean
Factory.doCreateBean(AbstractAutowireCapableBeanFactory.java:537)
at org.springframework.beans.factory.support.AbstractAutowireCapableBean
Factory.createBean(AbstractAutowireCapableBeanFactory.java:475)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getOb
ject(AbstractBeanFactory.java:304)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistr
y.getSingleton(DefaultSingletonBeanRegistry.java:228)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBe
an(AbstractBeanFactory.java:300)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean
(AbstractBeanFactory.java:195)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.
preInstantiateSingletons(DefaultListableBeanFactory.java:700)
at org.springframework.context.support.AbstractApplicationContext.finish
BeanFactoryInitialization(AbstractApplicationContext.java:760)
at org.springframework.context.support.AbstractApplicationContext.refres
h(AbstractApplicationContext.java:482)
at org.springframework.context.support.ClassPathXmlApplicationContext.<i
nit>(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.<i
nit>(ClassPathXmlApplicationContext.java:93)
at com.alibaba.dubbo.container.spring.SpringContainer.start(SpringContai
ner.java:50)
at com.alibaba.dubbo.container.Main.main(Main.java:80)
,
]

而且这个信息不停的打,并且看到的全是xxxMapper

难道是mybatismapper代理类的创建出现了问题?

尝试本地通过代码的方式启动服务,没有任何问题。

又尝试本地通过打出的zip包,通过java -jar的方式启动,也没有任何问题。

这个时候就很头疼了,定位不到问题,而且问题不能重现。

网上能搜索到关于mybatis启动报Stack overflow的错误,难道我们这个问题跟他也有关系?于是尝试看一下mybatismapper代理自动创建的相关资料。

通过这篇文章

MapperFactoryBean实例生成之后,Spring给它注入SqlSessionTemplate。而注入SqlSessionTemplate的过程中会向容器获取所有的Dao,对于已经在容器中的Dao所对应的bean可以直接获取返回,若还没有创建bean,则Spring又会先创建这个DaoMapperFactoryBean。创建MapperFactoryBean的时候会再次注入SqlSessionTemplate。就这样一直循环下去,直到所有的Dao都已经创建完毕,这个过程才算结束。

看来跟mybatis的关系应该很大,网上有有说mybatis Mapper有导致过stack overflow的错误,新想如果是stack overflow肯定应该是有明确的异常抛出,于是也是抱着尝试调整一下jvm的参数看看是否有惊喜。

-Xms1024m -Xmx1024m -XX:PermSize=256m -XX:MaxPermSize=256m -Xss256k

stack overflow应该调整Xss参数大小(-Xss512k)调整后重启,竟然成功了!竟然成功了!竟然成功了!

太不可思议了难道是stack overflow异常被吃掉了?而且mapper在创建的时候是递归,递归的层次越深越消耗stack大小,然后具体搜索mybatis导致stack异常的信息看到了这篇文章,上面就是说mybatis-spring工具包有问题将异常吃掉了,具体mybatis-spring中的那段代码我还在定位,定位好了在更新文章

解决方法

调整xss参数,从xss256k调整为xss512k