前言
本周在做测试系统的升级时在网络隔离的情况下遇到了maven的私有库依赖问题,被整的很惨,原本以为很了解的maven私有库依赖问题在实际应用中还是有不少意外情况要处理,为此特别进行了maven依赖机制和私有库打包和运行相关技术的调研,总结在这里方便日后查看和团队分享。
Maven依赖检索顺序
1.查看scope是否是system,若是system则不会去仓库中查找
2.若scope不是system,则先去本地仓库中查找是否有相应的依赖库,若不存在则进入下一步。若存在相应依赖,若存在lastupdated时间戳未过期就加入工程依赖,否lastUpdated时间戳过期则会进去远程仓库检索。[这个地方的逻辑不能100%确定,需要分析maven源码来确认。]
3.若本地仓库中没有找到相应的依赖,则会去远程仓库(中央仓库或私服)中查找是否有相应依赖,有就下载,否则进行下一步
4.报错。
因此可见若原来下载过某个依赖,但中间因为网络等其他因素造成依赖损坏,但是其lastUpdated时间戳已经更新,则会导致maven不会自动下载其依赖但构建可能会失败。这是最好的解决办法是将时间戳文件删掉或将整个依赖库都删掉
添加私有依赖库的主要方式
install到本地仓库
mvn install:install-file -Dfile=本地jar包目录 -DgroupId=groupId -DartifactId=artifactId -Dversion=version -Dpackaging=jar
若有nexus或其他私有库管理工具可以将本地的依赖直接deploy到私服上,以供其他小伙伴来共同使用这些依赖。
resources配置
上面的方法是比较正常的路线,但如果私有依赖库较多时工作量也是挺大的,而且要在多台机器共享的话还需要nexus私服,因此在某些特殊情况下无法使用,这里介绍一个直接利用maven插件的方法来解决私有依赖库的方式,可以通过版本管理工具来管理依赖库和pom文件,可以支持直接的拷贝等方式转移,对于离线和脱离nexus来说是非常方便的。
基本思路
1.将私有依赖库通过设置为system的scope或maven-compiler-plugin插件的方式加载到项目中
2.通过在build下设定resources的方式设定资源文件的路径的方式来将私有依赖库和其他库一并打包到jar或war。
3.通过标准的mvn clean package等指令打包即可。
具体例子
下面就以springboot的项目为例介绍。
项目路径如下图所示
我这里在根目录下新建了一个叫libs 的文件夹来保存私有的依赖库。
示例性的POM如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.zw.se2.demo</groupId>
<artifactId>demo</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.4.RELEASE</version>
</parent>
<packaging>jar</packaging>
<properties>
<main.basedir>${basedir}/../..</main.basedir>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
<spring.boot.version>1.5.4.RELEASE</spring.boot.version>
<spring-cloud.version>Dalston.SR1</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--下面是通过system的scope添加的依赖-->
<!--<dependency>-->
<!--<groupId>local</groupId>-->
<!--<artifactId>sdo-api</artifactId>-->
<!--<version>2.1.0</version>-->
<!--<systemPath>${project.basedir}/libs/sdo-api-v2.1.0.jar</systemPath>-->
<!--<scope>system</scope>-->
<!--</dependency>-->
</dependencies>
<build>
<resources>
<resource>
<directory>libs</directory>
<targetPath>BOOT-INF/lib/</targetPath>
<includes>
<include>**/*.jar</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<targetPath>BOOT-INF/classes/</targetPath>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
<compilerArguments>
<extdirs>libs</extdirs>
</compilerArguments>
</configuration>
</plugin>
</plugins>
</build>
</project>
通过这样的设置,直接可以通过标准的maven指令来打包和运行了,与标准程序没有任何区别。
直接拷贝也没有任何问题。
添加到java环境
若有权限修改系统环境,可以将依赖的私有库直接添加到系统默认的java的第三方依赖路径下:
%JAVA_HOME%/\lib\ext
但这个方法需要注意还是需要通过上面的system的scope或maven-compiler-plugin插件来将私有依赖库加载到项目中否则maven是编译不过去的,当然要是ide的话也需要将路径配置好了才行。
但这个方法没有办法对依赖库进行版本控制,同时在复制项目时由于依赖库是在java的目录下的因此十分容易出错。通过若多个项目共享环境则更容易出问题,因此要慎用。
当然不可否认这个方法时实行起来直接成本最低的。
总结
1.若有私服则强烈推荐使用deploy的方式来将私有依赖推到私服上,这样方便团队共同使用。特别是依赖库也同时在进行开发时,这个方法是唯一适用的方法,其他的方法出错概率极高,管理成本超高。
2.若没有私服或存在特殊应用场景,那么通过maven插件和设置资源目录的方式也是可以的。
3.依赖管理本来就是maven的主要工作内容,能交给maven的还是交给maven来处理吧,手动的依赖管理费时费力还容易出错。