maven, java中的依赖管理与项目构建

目录

1. 仓库

2. java项目结构

4.生命周期

4.1 compile

4.2 test

4.3 package

4.4 install

4.5 deploy

5. pom.xml 常用标签

5.1 变量复用

5.2 依赖相关

6. 依赖管理 与 冲突解决

6.1. 观察解析后的依赖

6.2. 为什么会遇到依赖冲突

6.3. 依赖传递的仲裁规则

6.4. 实际case 笔记

6.4.1 明确指定C的版本

6.4.2 依靠 exclude 排除传递依赖

6.4.3. 依靠scope 避免与运行容器的依赖冲突 

7. 配置继承与多模块


Maven,['meɪv(ə)n],项目构建管理工具,用于告诉编译器项目中各文件之间的依赖关系等。

pom.xml 文件指定了项目的依赖关系。

1. 仓库

Maven的仓库分为本地仓库和远程仓库。
本地仓库:是Maven在我们本机设置的仓库目录,默认目录为 当前用户目录/.m2/repository

C盘空间珍贵, 如何指定到别的磁盘呢? 添加下行配置即可.

<localRepository>D:\maven_local_repository</localRepository>


远程仓库:联网时才能用,从这里下载jar。

默认远程仓库因为访问量大,速度慢,所以可以自己临时替换远程仓库位置。
.m2/ 目录下有个settings.xml配置文件,在<mirrors>节点内部增加<mirror>节点就可以了。
一个示例:

<mirror>  
      <id>jboss-public-repository-group</id>  
      <mirrorOf>*</mirrorOf>  
      <name>JBoss Public Repository Group</name>  
     <url>http://repository.jboss.org/nexus/content/groups/public</url>  
</mirror> 

2. java项目结构

maven默认的文件存放结构如下:
/项目目录
        pom.xml 用于maven的配置文件
/src 源代码目录
        /src/main 工程源代码目录
                /src/main/java 工程java源代码目录
                /src/main/resources 工程的资源目录
        /src/test 单元测试目录
                /src/test/java
/target 输出目录,所有的输出物都存放在这个目录下
        /target/classes 编译之后的class文件


SNAPSHOT:如果一个版本包含字符串"SNAPSHOT",Maven就会在安装或发布这个组件的时候将该符号展开为一个日期和时间值,转换为UTC时间。例 如,"1.0-SNAPSHOT"会在2010年5月5日下午2点10分发布时候变成1.0-20100505-141000-1。

resources 资源文件的IO路径

 图:打包后, resources/ 目录下的文件与 /src/main/java/ 平级

可使用 当前类.class.getClassLoader().getResourceAsStream("other/a.xlsx") 获取 InputStream. 注意区别  当前类.class.getResourceAsStream("/other/a.xlsx") 两种用法中的path中的最开始的斜杠的有无. 

4.生命周期

从前到后依次是

compile、test、package、install、deploy。

4.1 compile

compile任务就是编译源码,并把编译后的class文件存放到target/classes中。
任务描述在<build>标签中,见下:
<build>
		<sourceDirectory>src/main/java</sourceDirectory>
		<testSourceDirectory>src/test/java</testSourceDirectory>
		<plugins>
			<plugin>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.5.1</version>
				<configuration>
					<source>1.8</source>
					<target>1.8</target>
				</configuration>
			</plugin>
		</plugins>
	</build>

4.2 test

自动执行junit @Test函数。并输出成功的用例和失败的用例。

4.3 package

打包。可参见插件 文章。

4.4 install

将自己的项目打包进本地仓库中。这样自己的其他项目就可以依赖它了。

常见错误

[ERROR] No compiler is provided in this environment. Perhaps you are running on a JRE rather than a JDK?

解决方法:Library中的jre变成jdk,下图:

附带源码

可以使用maven-source-plugin插件。

4.5 deploy

用于发布到远程仓库。

5. pom.xml 常用标签

5.1 变量复用

    <properties>标签.

    <properties>
            <spring.version>4.0.4</spring.version>
    </properties>
    <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
            <scope>provided</scope>
			<exclusions>
				<exclusion>
					<artifactId>log4j-over-slf4j</artifactId>
					<groupId>org.slf4j</groupId>
				</exclusion>
			</exclusions>
    </dependency>

5.2 依赖相关

  • 引入三方包依赖, 用 <dependency> 标签.
  • 传递依赖的排除, 用 <exclusions> 标签.
  • 指定依赖时机, 用 <scope> 标签

6. 依赖管理 与 冲突解决

6.1. 观察解析后的依赖

  • `IDEA|Project视图|External Libraries`, 以平级形式展示的是实际引入的三方包.
  • 也可用 mvn dependency:tree,  以层级形式展示依赖传递关系, 显式实际引入的三方包.
  • `IDEA|Maven| ${project}|Dependencies`, 展示每个三方包自己的依赖树, 灰色表明冲突时被舍弃.
  • 使用IDEA  Maven Helper 插件. 打开pom文件, 子窗口底部会有 {Text, Dependency Analyzer}, 对冲突分析很有用.

Maven Helper 插件 功能截图

6.2. 为什么会遇到依赖冲突

约定符号: A->B:v1 表示 项目A依赖于项目B的v1版本.

依赖场景:  自己的项目P,  P->A, P->B,  A->C:v1, B->C:v2 , 见上图, 因形状得名 菱形依赖.

冲突原因: C的v1与v2有函数签名等的变化, 导致 实际运行时类找不到或语法校验错误.

能解决的情形: C的某个版本可以兼容, 想办法调整 pom 内容, 明确对该版本的依赖即可.

不能解决的情形: A用的方法只在 C:v1 中有, B用的方法只在 C:v2 中有, 则无解.

6.3. 依赖传递的仲裁规则

maven 面对冲突时, 有自己的默认规则:

  • 最短路径优先
  • 最先声明优先
  • 版本低的优先

6.4. 实际case 笔记

6.4.1 明确指定C的版本

protobuf-java v2.5.0三方包中有个方法 , UnknownFieldSet com.google.protobuf.GeneratedMessage#getUnknownFields(),

swift_client 中有个类继承了该类,public static final class Messages extends GeneratedMessage {} , 然后重写了该方法, public final UnknownFieldSet com.alibaba.search.swift.protocol.SwiftMessage.Messages#getUnknownFields().

但在protobuf-javav2.4.1 中, getUnknownFields() 是 public final签名, 所以被omit之后, 导致报错.

解决办法: 按照最短路径优先, 直接新增一个 dependency, 指明版本为 2.5.0, 即可解决.

6.4.2 依靠 exclude 排除传递依赖

error-3sBZE>Caused by: com.alibaba.glaucus.client.domain.GlaucusRuntimeException: TppErrorCode-[SOLUTION_EXECUTE_ERROR]-[null], DETAIL_INFO: Host(11.227.244.142),solutionId(59278)
error-3sBZE>Caused by: 
java.lang.LinkageError: loader constraint violation: when resolving method 'org.apache.http.impl.nio.client.HttpAsyncClientBuilder org.apache.http.impl.nio.client.HttpAsyncClientBuilder.setDefaultRequestConfig(org.apache.http.client.config.RequestConfig)' 
the class loader com.alibaba.kondyle.loader.solution.loader.SolutionClassLoader @717caa80 of the current class, com/aliyun/openservices/eas/predict/http/PredictClient, 
and 
the class loader org.apache.catalina.loader.ParallelWebappClassLoader @66b5c7cc for the method's defining class, org/apache/http/impl/nio/client/HttpAsyncClientBuilder, 

因为 httpcore 足够基础, 要在很多依赖中写 exclude. 

 6.4.3. 依靠scope 避免与运行容器的依赖冲突 

如果冲突不来自于 传递依赖, 则可以靠 provided.

可以调整 <scope> 标签, 默认为 compile, 覆盖所有时机..

  • provided: 编译时依赖, 打包分发时不依赖, 如 一些 servlet 容器.
  • test: 测试时依赖, 如 junit.

7. 配置继承与多模块

见  https://blog.csdn.net/chuchus/article/details/47100795

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值