乐趣区

如何给非maven的javaweb项目霸王硬上弓

最近在公司搭建了一套代码安全质量分析平台 – 著名的 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 会从这个搜索路径里,按顺序去找依赖的类,请注意这里的排序:

  1. 先是 jdk
  2. 然后到 lib 里的 jar
  3. 最后到 -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 的冷门使用了。可气的是网上似乎找不到关于这种情况的解决方案,特意注册一个博客,以受批判。

退出移动版