Maven
maven导入jar包时冲突问题
maven工厂要导入jar包的坐标,就必须考虑解决jar包冲突问题
方式1:第一声明优先原则:哪个jar包的坐标在靠上的位置,这个jar包就是先声明的。先声明的jar包坐标下的依赖包可以优先进入项目中。
方式2:路径近者优先原则。直接依赖路径必传递依赖路径近,那么最终项目进入的jar包会是路径近的直接依赖包。
-
直接依赖:项目中直接导入的jar包,就是该项目的直接依赖包
-
传递依赖:项目中没有直接导入的jar包,可以通过项目直接依赖jar包传递到项目中。
⭐️方式3:直接排除法。当我们要排除某个jar包下依赖包,在配置exclusions
标签的时候,内部可以不写版本号。因为此时依赖包使用的版本和默认和本jar包一样。
版本锁定:我们可以把A项目中主要的jar包的坐标锁定,那么其他依赖该项目的项目中,即便是有同名jar包直接依赖,也无法覆盖。
使用场景: maven工程是可以分父子依赖关系的。凡是依赖别的项目后,拿到的别的项目的依赖包,都属于传递依赖。比如:当前A项目,被B项目依赖。那么我们A项目中所有jar包都会传递到B项目中。 B项目开发者,如果再在B项目中导入一套ssm框架的jar包,对于B项目是直接依赖。那么直接依赖的jar包就会把我们A项目传递过去的jar包覆盖掉。
<!-- 统一管理jar包版本 -->
<properties>
<spring.version>5.0.2.RELEASE</spring.version>
<slf4j.version>1.6.6</slf4j.version>
</properties>
<!-- 锁定jar包版本 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
</dependencyManagement>
maven工程的拆分和聚合思想
/Users/silince/Develop/MagicDontTouch/IdeaProjects/Java EE/maven/maven_ssm_parent
工程和模块的区别:
-
工程不等于完整的项目,模块也不等于完整的项目,一个完整的项目看的是代码,代码完整就可以说是一个完整的项目。
-
工程天生只能使用自己内部资源,工程是独立的。后天可以和其他工程或模块建立关联关系。 模块天生不是独立的,天生是属于父工程的,模块一旦创建,可以用父工程的所有资源。
-
父子工程关系,子模块可以使用父工程所有资源。子模块之间是没有任何关系的。
-
父子工程不需要建立关系,继承关系是先天的。
-
平级直接的应用叫依赖,依赖不是先天的,需要后天建立。
拆分后的启动方式:
-
方法 1:在 ssm_web 工程的 pom.xml 中配置 tomcat 插件运行。运行 ssm_web 工程它会从本地仓库下载依赖的 jar 包,所以当 ssm_web 依赖的 jar 包内容修 改了必须及时发布到本地仓库,比如:ssm_web 依赖的 ssm_service 修改了,需要及时将ssm_service 发布到本地仓库。
-
方法 2:在父工程的 pom.xml 中配置 tomcat 插件运行,自动聚合并执行。 推荐方法 2,如果子工程都在本地,采用方法 2 则不需要子工程修改就立即发布到本地仓库, 父工程会自动聚合并使用最新代码执行。
-
ps:如果子工程和父工程中都配置了 tomcat 插件,运行的端口和路径以子工程为准。
Maven POM中的各种scope的行为总结
compile:默认的scope。任何定义在compile scope下的依赖将会在所有的class paths下可用。maven工程会将其打包到最终的atifact中。如果你构建一个WAR类型的artifact, 那么在compile scope下引用的JAR文件将会被集成到WAR文件内。
provided:这个scope假定对应的依赖会由运行这个应用的JDK或者容器来提供。最好的例子就是servlet API。任何在provided scope下定义的依赖在构建时的类路径里是可用的,但是不会被打包到最终的artifact中。如果是一个WAR的文件,servlet API在构建时的类路径里是可用的,但是并不会被打包到WAR文件中。
runtime:在runtime scope下定义的依赖只会在运行期可用,而在构建期的类路径下不可用。这些依赖将会被打包到最终的artifact中。比如你有一个基于web的应用需要在运行时访问MySQL数据库。你的代码没有任何MySQL数据库驱动的硬依赖。你的代码仅仅是基于JDBC API来编写,在构建期并不需要MySQL数据库驱动。然而,在运行期,就需要相应的驱动来操作MySQL数据库了。因此,这个驱动应该被打包到最终的artifact中。
test:只用于测试编译的依赖(比如JUnit) ,execution必须定 义在test scope下。这些依赖不会被打包到最终的artifact中。
system:于provided scope很像。唯一的区别在于, 在system scope中,你需要告诉Maven如何去找到这个依赖。如果你要引用的依赖在Maven仓库中不存在时,就可以用这个scope。不推荐使用system依赖。
import:import scope只能用在dependencyManagement
里面。我们知道Maven的继承和Java的继承一样,是无法实现多重继承的,如果10个、20个甚至更多模块继承自同一个模块,那么按照我们之前的做法,这个父模块的dependencyManagement
会包含大量的依赖。如果你想把这些依赖分类以更清晰的管理,那就不可能了,import scope
依赖能解决这个问题。你可以把dependencyManagement
放到单独的专门用来管理依赖的pom中,然后在需要使用依赖的模块中通过import scope
依赖,就可以引入dependencyManagement
。
依赖传递
作用域是test的包不会传递到引用这个项目的其它项目,但如果不是test会传递依赖到其它项目。
如:项目A中有一个依赖包junit4.10,它的作用域是test
现在有一个项目B,引用项目A,如果项目B要使用junit4.10就必须自己重新定义依赖关系。【因为不会传递依赖,所以不会从项目A中得到】
但:如果作用域是其它的,不是test,那么项目B可以直接使用不用自己再定义一个依赖关系。【因为会从项目A中自动传递依赖,而得到】
既已览卷至此,何不品评一二: