最近在公司搭建了一套代码安全质量分析平台–著名的SonarQube开源版本,再配合jenkins组成自动化流程。
jenkins调用maven做源码编译打包,然后调用SonarQube进行代码扫描,看起来一点问题都没有。
但是问题来了,公司的项目都是非maven结构的javaweb项目。
上网查了一下,非maven结构的javaweb项目通过更多的定制配置,是完成可以用maven来编译打包的。
这两天碰到公司一个javaweb项目,结构比较特殊,项目里除了引用jar包,还引用了class文件,类似下面的结构
在网上查了半天,找不到这样项目结构使用maven的相关实践。运气比较好的是,之前帮公司配置 pinpoint agent 的时候,恰好了解了一个jvm参数 -classpath,经过在家的一系列实验,终于把这样项目结构的工程编译打包,pom的关键配置如下:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
<verbose>true</verbose>
<showWarnings>true</showWarnings>
<compilerArgs>
<arg>-extdirs</arg>
<arg>WebContent/WEB-INF/lib</arg>
<arg>-classpath</arg>
<arg>ImportedClasses</arg>
</compilerArgs>
</configuration>
</plugin>
在<compilerArgs>里设置编译用的jvm参数,除了常规引用的放在WebContent/WEB-INF/lib里的所有jar包,还有ImportedClasses目录下的
所有class文件。
这样就可以完美的进行编译和打包了。
回到公司配置好,编译,报错。有一个类的一个方法找不到。
这个项目还有一个特别之处,就是其中一个引用的class文件(且称它为a.class),跟其中一个jar包里的class文件的包名、类名一模一样,反编译看,两者内容却不一样。
按照上面的配置方法,maven在调用javac编译源码,会按顺序扫描依赖的文件,直到碰到第一个目标。
看下图,maven会从这个搜索路径里,按顺序去找依赖的类,请注意这里的排序:
- 先是jdk
- 然后到lib里的jar
- 最后到-classpath 指定的 ImportedClasses
回到那个报错,因为源码里引用的是 ImportedClasses 里的 a.class 才有的方法,而非 jar 里的a.class,当maven在扫描依赖文件时,首先会碰到 jar 里的 a.class,然后发现这个类没有这个方法,于是报错。
好了,说到这里,解决思路呼之欲出,就是让 ImportedClasses 的顺序比 lib 靠前。
这个方案网上找了一通,可能是因为拙略的搜索技巧,找不到别人提供的经验。
自己各种尝试,暂时也没有找到能调整顺序的方法。
舍弃javac 的-extdirs参数,全部依赖写到-classpath里,就可以自己掌控依赖的搜索顺序了。
<compilerArgs>
<arg>-classpath</arg>
<arg>ImportedClasses;WebContent/WEB-INF/lib/fastjson-1.2.47.jar</arg>
</compilerArgs>
把ImportedClasses写在所有jar之前,编择成功。
这个方法的缺点就是,当以来的jar包很多的时候,这个值就变得很长,因为要把每一个jar的路径写上去。
碰到这样的项目结构机率一般比较小,所以这也算是一个maven的冷门使用了。遗憾的是网上似乎找不到关于这种情况的解决方案,特意注册一个博客,以受批判。