spring+mybatis启动NoClassDefFoundError异常分析三部曲之三:改spring源码,取详细错误

在上一章《spring+mybatis启动NoClassDefFoundError异常分析三部曲之二:定位错误》中,我们通过打断点的方式,在spring初始化时创建bean的位置单步执行代码,定位到了应用启动失败的原因是由于AbstractAutowireCapableBeanFactory.createBean方法被多层嵌套式调用从而导致了栈内存被耗光,抛出了StackOverflowError异常,但由于doCreateBean方法捕获异常并抛出新的异常,导致启动的输出信息中看不到原始的错误堆栈,本章我们一起来修改并编译spring源码,使得错误发生的时候及时打印出有效的堆栈信息,以便我们定位问题; 关于修改和编译spring源码的方法,您可以参照《修改和编译spring源码,构建jar(spring-context-4.0.2.RELEASE)》,此处我们修改的不是spring-context,而是spring-bean,如果读者您觉得准备一个修改和编译spring-bean源码的环境太费时太麻烦,也可以从我的git上直接下载可运行的工程,地址是:git@github.com:zq2599/blog_demos.git,这里面有多个工程,本次用到的工程如下图红框所示:

创建这个工程的主要步骤,在《修改和编译spring源码,构建jar(spring-context-4.0.2.RELEASE)》一文中已经说过了,为了编译通过,此处把几处重要的改动再说明一下:

  1. 将官方的spring-beans-4.0.2.RELEASE.jar文件解压,在java/org/springframework/beans/factory/xml目录下,将所有的xsd文件复制到我们工程的同名目录下;
  2. 工程的pom中增加插件,以便打包的时候可以复制xsd文件到jar包,如下:
<plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <configuration>
                    <archive>
                        <addMavenDescriptor>false</addMavenDescriptor>
                    </archive>
                </configuration>
            </plugin>

            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>build-helper-maven-plugin</artifactId>
                <version>1.8</version>
                <executions>
                    <execution>
                        <id>add-resource</id>
                        <phase>generate-resources</phase>
                        <goals>
                            <goal>add-resource</goal>
                        </goals>
                        <configuration>
                            <resources>
                                <resource>
                                    <directory>src/main/java</directory>
                                    <includes>
                                        <include>**/*.xsd</include>
                                    </includes>
                                </resource>
                            </resources>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
  1. GroovyBeanDefinitionReader.java编译未过,本次实战我们不会涉及到Groovy相关的代码,所以此处直接将此文件中的红叉部分注释掉,修改的地方有如下三处:

经过了上面的修改,我们本地的spring-bean工程应该能正常编译的构建程jar包了,开始改源码吧:

根据我们之前的分析,启动失败的位置是在执行AbstractAutowireCapableBeanFactory.createBean的时候,调用populateBean方法抛出了异常,又被try catch将异常捕获处理了,如下图:

所以此次改动就在这里,我们添加更详细的输出,以便在异常的时候可以看到更多的输出信息:

  1. createBean方法会被反复迭代调用,如果每次抛异常都打印信息就太多了,我们不需要这么多,所以加个是否已经打印过异常的标志位,初始值是false,打印一次就改为true:
private static boolean hasErrorPrinted = false;
  1. 把上面截图中的代码改成下图这样,捕获异常后,如果hasErrorPrinted为false,就把异常打印出来,并且将hasErrorPrinted改为true:
  1. 修改完毕了,在工程目录下执行mvn clean package -U,执行成功后在target目录下可以生成最新的spring-beans-4.0.2.RELEASE.jar文件,复制到tomcat的webapp下的lib中替换原有文件,启动tomcat看一下,我们捕获的异常信息被完整的打印出来了,多层迭代导致的StackOverflowError,如下图:

至此,spring启动异常的问题三部曲就全部结束了,除了阅读源码,debug调试,我们还尝试了修改源码,希望此系列的实战能对您今后深入学习spring有所帮助。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏水击三千

asp.net MVC 验证注解

对于Web系统,对于用户的输入验证是必须的。不仅需要在客户端对用户的输入进行验证,在服务端也需要对用户的执行进行验证。 asp.net MVC中对于验证提供了一...

2279
来自专栏互联网杂技

React数据流和组件间的通信总结

首先,我认为使用React的最大好处在于:功能组件化,遵守前端可维护的原则。 先介绍单向数据流吧。 React单向数据流:   React是单向数据流,数据主要...

3417
来自专栏13blog.site

Spring+SpringMVC+MyBatis+easyUI整合进阶篇(九)Linux下安装redis及redis的常用命令和操作

redis简介 ? Redis是完全开源免费的,遵守BSD协议,是一个高性能的key-value数据库。 Redis与其他key-value缓存产品有以下...

2746
来自专栏smy

webpack打包速度和性能再次优化

一. 改单dll为双dll ? 因为上图原因,使用CommonsChunkPlugin时,导致其打包出来的vendors.js内的模块ID会因为其他文件引用模块...

4588
来自专栏V站

PHP网址缩短算法代码(修复PHP7.0问题)

每个网址用6个字符代替,(32^6) 最多可以拥有1,073,741,824个短网址。当然,你还可以记录更详细的信息,如访问记录,创建时间等。如果真不够用了,还...

1932
来自专栏Java技术分享

第九章:Shiro的Web——深入浅出学Shiro细粒度权限开发框架

Shiro可以和普通web集成的,但考虑到现在的应用基本都会使用spring,所以就不去讲最基本的web集成了。跟Spring集成的方式前面已经讲过了。

1758
来自专栏Ryan Miao

Spring cache简单使用guava cache

Spring cache简单使用 前言 spring有一套和各种缓存的集成方式。类似于sl4j,你可以选择log框架实现,也一样可以实现缓存实现,比如ehcac...

4027
来自专栏阮一峰的网络日志

浏览器加载 CommonJS 模块的原理与实现

就在这个周末,npm 超过了 cpan ,成为地球上最大的软件模块仓库。 npm 的模块都是 JavaScript 语言写的,但浏览器用不了,因为不支持 Com...

3468
来自专栏云瓣

探寻 webpack 插件机制

webpack 可谓是让人欣喜又让人忧,功能强大但需要一定的学习成本。在探寻 webpack 插件机制前,首先需要了解一件有意思的事情,webpack 插件机制...

2697
来自专栏阿杜的世界

Spring实战2:装配bean—依赖注入的本质主要内容

任何一个成功的应用都是由多个为了实现某个业务目标而相互协作的组件构成的,这些组件必须相互了解、能够相互协作完成工作。例如,在一个在线购物系统中,订单管理组件需要...

772

扫码关注云+社区