问题背景
记得一几年的时候刚使用maven不久,对maven还不是很熟悉。只知道maven是管理jar包的。对maven的一些工程结构,规范不是很了解。
项目中采用的技术框架是mvc和mybatis。mybatis中需要大量的map xml文件,xml文件中是描述sql查询等语句的。sqlSessionFactory在初始化时会解析这些文件构建statement并注入到mybatis容器中。这样我们在使用dao接口层就可以根据statement的namespace匹配到唯一的xml实现,最终实现数据的持久化。
但是刚开始我们把xml文件放在了 src/main/java目录中。启动没有问题,在调用dao接口时总是报错,不存在对应的statement。通过日志分析是说没有找到对应的实现。
问题原因&排查过程
报错原因已经很清楚,就是没有找到对应的实现,但是我们认真对比过,命名、大小写、namespace都没有问题,mybatis的配置也没有问题。最终我们怀疑到编译问题。
在工程编译目录target目录中,查找xml有没有被编译。最后发现target目录中的classes没有xml文件。当时没想明白为什么编译时idea把xml文件忽略了。
idea在编译maven工程时是通过maven插件读取工程的pom文件然后按照约定配置进行编译的。比如编码、jdk版本、source目录等。
如果xml文件被遗漏了,那么肯定是pom文件的resource配置有问题。最后我们通过查询资料发现。maven本身的原则是约定大于配置,xml文件在maven工程中默认的路径是放在src/main/resources目录下的。src/main/java目录下一般只放java文件,如果java目录下也有xml文件,都会被maven忽略,而idea本身也是通过maven插件来编译maven工程的,所以同样也会忽略xml文件。下图是maven工程的结构
问题解决
如果我们按照maven的规范把xml文件放到resources目录下,那么肯定是没问题的,xml肯定也可以编译到classes目录中。但是如果我们没有按照规范,那么就需要手动指定下resource的目录以及包含哪些文件类型
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
总结
- 很多事情要遵守约定,良好的约定往往会让事情变得简单很多,就像小组团队中约定好的交流方式,工作方式,前后端数据的交互规范等等,都属于按照我们已经习惯的制定好规范而已。
- 任何框架只要不懂原理,遇到问题都有可能让你变得束手无策,就像本文中的问题,其实本身就是编译的问题,而且这种情况有时候在eclipse中并不会出现,因为eclipse的编译和idea又有所不同,它不是完全按照maven的规范去编译的。
- 学会思考