简述
java开发中能够应用maven来治理依赖,引入依赖,构建最终jar文件,当然其中也可能须要解决依赖抵触问题。

治理依赖:通过<dependencyManagement>,申明依赖版本,进行依赖的版本控制的。
引入依赖:通过<dependency>,进行依赖的理论引入。
构建jar包:在须要打包的模块中增加<build>并退出定制插件plugin进行jar生成。
依赖抵触:通过工具或者命令行排查抵触的依赖后,应用exclusion来排出抵触的依赖。

注:

依赖抵触能够应用idea的mavenhelper插件来查看,简略直观,也能够命令行应用mvn dependency:tree -Dverbose > tree.txt,在文件中检索conflict关键字。

maven应用前,须要设置好setting.xml配置文件,如镜像仓库。

maven的打包命令mvn clean package -Dmaven.test.skip=true
指定配置文件打包mvn clean package -s setting.xml -Dmaven.test.skip=true
maven的仲裁机制:门路最近者优先,门路雷同第一声明者优先(门路间隔是从打包模块的pom开始算,第一申明是pom中申明的前后程序)

maven罕用标签的应用
的根本应用
次要解说的内容:依赖罕用的两种援用形式,依赖的排除形式,依赖的作用域,<option>标签。

仓库引入

<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
复制代码

本地引入

注:须要在<build>中<plugin>中需增加<includeSystemScope>true</includeSystemScope>

<dependency>
<groupId>org.hibernate</groupId>
<artifactId>kingbase8-hibernatedialect</artifactId>
<version>5.2.17.Finaldialect</version>
<scope>system</scope>
<systemPath>${project.basedir}/../../../lib/hibernate-5.2.17.Finaldialect.jar</systemPath>
</dependency>
复制代码

依赖排除

<dependency>

<groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>${mybatis-plus.version}</version>

<!--须要排除的依赖项-->

<exclusions><!--排除的依赖无需申明版本号-->    <exclusion>        <groupId>com.github.jsqlparser</groupId>        <artifactId>jsqlparser</artifactId>    </exclusion></exclusions>

</dependency>
复制代码

依赖的作用域标签<scope>,其默认值为compile。

<!-- Lombok -->
<dependency>

<groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><scope>provided</scope>

</dependency>
复制代码

拓展:<scope>import</scope> 只能在<dependencyManagement> 模块中应用,用于解决maven的单继承问题。

<option>标签,固定值为true

<option>示意这个依赖是须要抉择是否引入的,如果须要引入则须要显示申明。
举例:下方代码块是B模块的pom文件,A我的项目将B我的项目作为依赖后,这些带<option>的依赖并不会被引入,不会打进jar包,如果须要引入则显示的增加申明。
<dependencies>

<dependency>    <groupId>mysql</groupId>    <artifactId>mysql-connector-java</artifactId>    <version>5.1.10</version>    <optional>true</optional><dependency><dependency>    <groupId>postgresql</groupId>    <artifactId>postgresql</artifactId>    <version>8.4-701.jdbc3</version>    <optional>true</optional><dependency>

</dependencies>
复制代码

拓展常识:<classifier>标签,提供一个新的维度定义jar,个别为不同jdk版本生成jar文件

maven-resp (maven仓库)
└── org

└── apache    └── maven        ├── maven-artifacr-3.8.1-calss1.jar (jdk8生成一个jar)        └── maven-artifacr-3.8.1-calss2.jar  (jdk21生成一个jar)

在pom文件中辨别环境的中增加<classifier>calss1</classifier>或<classifier>calss1</classifier>则不同环境生成不同jar文件
样例:
<properties>

  <classifier>default</classifier>

</properties>
<profiles>
<profile>

<id>jdk8</id><properties>  <classifier>calss1</classifier></properties>

</profile>
<profile>

<id>jdk21</id><properties>  <classifier>calss2</classifier></properties>

</profile>
</profiles>
<bulid>
<plugins>

<plugin>  <groupId>org.apache.maven.plugins</groupId>  <artifactId>maven-jar-plugin</artifactId>  <version>3.2.0</version>  <executions>    <execution>      <id>default-jar</id>      <goals>        <goal>jar<goal>      </goals>      <configuration>        <classifier>${classifier}</classifier>      </configuration>     </execution>   </executions> </plugin> 

</plugins>
</build>
复制代码
我的项目A,依赖B我的项目,并且须要mysql驱动
<dependencies>
<dependency>

    <groupId>project-b</groupId>    <artifactId>project-b</artifactId>    <version>b-version</version><dependency><!--因为B模块中mysql驱动是可选的,所以A模块须要mysql驱动得显示引入--><dependency>    <groupId>mysql</groupId>    <artifactId>mysql-connector-java</artifactId>    <version>5.1.10</version><dependency>

</dependencies>
复制代码
的根本应用

      <plugin>                <groupId>org.springframework.boot</groupId>                <artifactId>spring-boot-maven-plugin</artifactId>                <version>${spring-boot.version}</version>                <executions>                    <execution>                        <goals>            <!--1.在原始Maven打包造成的jar包根底上,进行从新打包,            新造成的jar包岂但蕴含利用类文件和配置文件,            而且还会蕴含利用所依赖的jar包以及Springboot启动相干类(loader等),            以此来满足Springboot独立利用的个性;                2.将原始Maven打包的jar重命名为XXX.jar.original作为原始文件;-->                            <goal>repackage</goal>                        </goals>                    </execution>                </executions>      <configuration>        <!--将本地jar包打入构建生成的jar文件中-->                    <includeSystemScope>true</includeSystemScope>                </configuration>            </plugin>

复制代码
微服务的目录构造
以当初宽泛风行的springboot多个微服务来作为介绍模板,一个微服务能够作为一个单体我的项目对待。
├── common (公共模块)
│ └── pom.xml
├── services(微服务模块)
│ ├── common(微服务之间的公共模块)
│ │ └── pom.xml
│ ├── service1(某微服务1的聚合模块)
│ │ ├──api(提供调用接口的模块)
│ | | └── pom.xml
│ | ├──specific-service(实现具体性能的模块)
│ | | └── pom.xml
│ │ └── pom.xml
│ ├── service2(某微服务2的聚合模块)
│ │ ├──api(提供调用接口的模块)
│ | | └── pom.xml
│ | ├──specific-service(实现具体性能的模块)
│ | | └── pom.xml
│ │ └── pom.xml
│ └── pom.xml
├── settings.xml (maven的配置文件)
└── pom.xml
复制代码
构造划分:聚合模块,依赖模块,实现模块
聚合模块
作用:聚合用于疾速构建maven工程,一次性构建多个我的项目/模块。
罕用标签

<packaging>:这是聚合模块必须要有的标签内容为pom,示意这是一个聚合模块(没有代码),用来治理多个模块。
<module>: 标签用于指定治理的那些模块,不记录模块治理的模块(浅援用)。
<dependencyManagement>:申明依赖版本,子模块引入依赖无需写入版本号,对立治理依赖版本。
<pluginManagement>,申明插件,治理插件配置,子项目间接继承,无需反复编写配置规定。
<properties>申明变量,用于对变量的治理,如版本号,通过${}取值。

依赖模块和实现模块
如api和common只提供工具和性能反对的模块称其依赖模块,而实现模块则是一个用于打包部署运行的具体微服务模块。
依赖模块罕用标签

<dependency>:引入所需依赖
packaging: 须要把代码打包,个别为jar

微服务模块罕用标签

<dependency>:引入所需依赖
packaging: 须要把代码打包,个别为jar(放在web容器则为war)
<build>:对于一个springboot我的项目,具体微服务模块须要通过build指定一个构建形式,如指定springboot-maven-plugin来进行构建。

JVM加载类
JVM会依据程序加载class文件,如果全限定名反复,前面的class将会被疏忽。
如果存在同类名的class能够思考:

移除反复的class
写类加载器来加载特定的class
扭转classpath里的程序

springboot生成jar构造目录
阿里的一些开发标准
【强制】禁止在子项目的 pom 依赖中呈现雷同的 GroupId,雷同的 ArtifactId,然而不同的 Version。
阐明:在本地调试时会应用各子项目指定的版本号,然而合并成一个 war,只能有一个版本号呈现在最初的 lib 目录 中。已经呈现过线下调试是正确的,公布到线上却出故障的先例。
【举荐】所有 pom 文件中的依赖申明放在语句块中,所有版本仲裁放在 语句块中。
阐明:里只是申明版本,并不实现引入,因而子项目须要显式的申明依赖,version 和 scope 都读取自父 pom。而所有申明在主 pom 的里的依赖都会主动引入,并默 认被所有的子项目继承。
【强制】二方库的新增或降级,放弃除性能点之外的其它 jar 包仲裁后果不变。如果有扭转,必须明确评 估和验证。
阐明:在降级时,进行 dependency:resolve 前后信息比对,如果仲裁后果齐全不统一,那么通过 dependency:tree 命 令,找出差别点,进行排除 jar 包。
【强制】依赖于一个二方库群时,必须定义一个对立的版本变量,防止版本号不统一。
阐明:依赖 springframework-core,-context,-beans,它们都是同一个版本,能够定义一个变量来保留版本: ${spring.version},定义依赖的时候,援用该版本。
开发中遇见的问题
某些包没有打入生成jar中

在idea开发实现后,生成镜像上云中发现微服务j启动ar报错,找不某个类,查看jar包发现某个依赖未打入jar包,jar为spring-boot-configuration-processor,检索引入中央,发现其引入作用域<scope>option<scope>,将其正文后,查看idea侧边maven也的确通过common引入,打包后仍然未打入jar包,将此依赖间接引入微服务打包后依赖引入胜利,但各个微服务都有引入,须要都复制一份有些麻烦,后将其从父工程根pom引入,打包后依赖引入胜利。只有正文掉作用域也不失效,其起因未知。
另一次就是pom引入本地jar包,但打包未增加<includeSystemScope>true</includeSystemScope>导致打包未打入jar。

jar包抵触

mybatis-plus-boot-starter中引入了jsqlparser依赖,然而mavenhelper未检测到,idea每次编译都会产生一个低版本的jsqlparser,因为开始不分明低版本的来处,导致节约了很多精力。
jsqlparser与pagehelper版本不匹配导致,办法不存在报错,最终通过查问到一个匹配版本解决。

某些二次封装的包与以前包全限定类名统一并且接口内容不统一产生谬误

如对一些罕用依赖进行了二次封装,然而接口办法有差异,导致编译时呈现谬误。

莫名其妙的循环依赖问题:增加了依赖或者改了一点无关的代码,循环依赖报错就会呈现,按情理低版本springboot能够通过三级缓存来解决循环依赖,然而并不失效。

抱着疑难,我找到了程序员导师:Google来求助,最终兜兜转转找到了github里spring-framework的一个issue,提的就是这个问题:
github.com/spring-proj…
能够看到这个issue从2016年首次被提出,到2019年reopen,实际上始终都没有找到过起因。issue里好几个人遇到了和我一样的问题:一样的代码,在不同的环境上编译,进去的jar包有的能运行,有的却报错。
spring的保护人员可能是感觉循环依赖不该当在程序中呈现,甚至目前springboot2.6版本曾经齐全不容许循环依赖了,所以对这个issue也就没有能源去解决。