Maven的爱恨情仇

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/xcbeyond/article/details/90547115

前言

    在如今的互联网项目开发当中,特别是Java开发中,可以说Maven是随处可见。Maven的仓库管理、依赖管理、继承和聚合等特性为项目的构建提供了一整套完善的解决方案,可以说如果你搞不懂Maven,那么一个多模块的项目足以让你头疼,依赖冲突就会让你不知所措,甚至搞不清楚项目是如何运行起来的。相信使用过Maven的人,一定曾经被Maven伤害过,但又不得不去让它来伤害,谁让它能给项目的构建提供便利呢。

    最近在微信群中,不断有人在使用Maven构建项目时,遇到了各种问题。一些问题也是大家经常遇见的,在此,博主就Maven的爱恨情仇,来说道说道,使用时能够得心应手。

 

为什么要使用Maven

    通常在一个项目中,我们会使用一些第三方类库,来提高开发速度,而不是闭门造车,毕竟在当今软件飞速发展的潮流下,不断涌现、开源出一些优秀的类库,供咱们灵活使用。在未使用Maven时,通常需要在项目中建立一个lib目录,在其中放着项目所依赖的各种类库,这样提交到SVN或GIT之后, 每个开发人员检出项目到本地,这样所有开发人员就会拥有统一的依赖类库。 但这样务必面临着下面这些问题:
1、依赖冗余,浪费空间

    随着公司项目的变大、变多,模块的增多,这种方式就会面临一些问题。不同项目,不同模块都可能会引用相同的依赖。当每个模块都把自己的依赖提交到SVN或GIT,那么相同的依赖就会占用服务器SVN或GIT的Repository很大的空间,造成空间浪费。 
2、版本问题

    如果一个项目中依赖的版本和另一个项目依赖的版本不一致。比如这个项目依赖spring-boot-starter-parent-1.5.9.RELEASE,而另一个可能依赖spring-boot-starter-parent-2.0.0.RELEASE, 当合并两个项目发布的时候,可能因为这种依赖类库详细版本信息的缺失,造成版本混乱冲突等问题。

3、管理问题

    随着项目的延续,项目依赖的类库可能需要更新,这时就需要不断从网上或通过其他途径,来替换lib目录下依赖的类库jar包文件,给依赖类库的管理带来了不便。

 

    为了解决上面依赖类库管理过程中出现的问题,我们需要寻求另一种依赖管理方式,即:一种集中式的依赖管理方式。各个项目只要通过统一的依赖描述文件(pom.xml)来指定自己需要的依赖就可以, 而不用自己来管理真正的依赖库,因为所有的项目都使用了同一个中央依赖库(中央仓库), 所以即使各个项目中有相同的依赖, 也不会出现依赖冗余的问题。 在依赖类库需要升级时,只需修改pom.xml即可方便升级更新。这种新的依赖管理方式,则是Maven,是基于POM的一款进行项目依赖管理,构建管理和项目信息管理的工具。

 

    回想一下,当你新到一家公司或新进入一个项目,安装完JDK后就会安装配置Maven,或许需要修改settings.xml文件,比如你可能会从其他人那里copy一段配置到你的settings.xml中(私服的一些配置)。接下来,你会到IDEA或者Eclipse中进行Maven插件配置,然后你就可以在工程中的pom.xml里面开始添加、修改<dependency>标签来管理jar包,在Maven规范的目录结构下进行编写代码,最后你会通过插件的方式来进行测试、打包、部署、运行。

 

    上面讲述了我们为什么使用Maven,什么时候使用它,下面就开始看看它的一些使用方法、常见问题:

1、本地仓库?Maven到底有哪些仓库?它们什么关系?

 

本地仓库路径配置:

<localRepository>E:/.m2/repository</localRepository>

    你要的依赖jar包,不可能每次都要从互联网去下载,特别是有的公司或项目根本就没有外网的情况,多费劲,所以本地仓库就是相当于加了一层jar包缓存,先到这里来查。如果这里查不到,那么就去私服上找,如果私服也找不到,那么去中央仓库去找,找到jar后,会把jar的信息同步到私服和本地仓库中。

    私服:就是公司内局域网的一台服务器而已,当你的工程Project-A依赖别人的Project-B的接口,怎么做呢?没有Maven的时候,当然是copy Project-B jar到你的本地lib中引入,那么Maven的方式,很显然需要其他人把Project-B deploy到私服仓库中供你使用。因此私服中存储了本公司的内部专用的jar,不仅如此,私服还充当了中央仓库的镜像,说白了就是一个仓库代理!

    中央仓库:该仓库位于互联网上,由Maven团队来维护,地址是http://repo1.maven.org/maven2/。此外,像阿里也对外提供了中央仓库,地址是http://maven.aliyun.com/nexus/content/groups/public,下载速度比Maven的还快,推荐使用。

 

2、关于<dependency>的使用

pom.xml依赖

<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
      <version>2.0.0.RELEASE</version>
</dependency>

    从上图可以看出,通过groupId、artifactId、version,就可以在仓库中查找到依赖jar的位置。

    一般而言,我们可以到私服上输入artifactId进行搜索,或者到http://search.maven.org/、http://mvnrepository.com/上进行查找确定依赖jar。

 

version分为开发版本(Snapshot)和发布版本(Release),那么为什么要分呢?

    在实际开发中,我们经常遇到这样的场景,比如A服务依赖于B服务,A和B同时开发,B在开发中发现了BUG,修改后,将版本由1.0升级为2.0,那么A必须也跟着在POM.XML中进行版本升级。过了几天后,B又发现了问题,进行修改后升级版本发布,然后通知A进行升级...可以说这是开发过程中的版本不稳定导致了这样的问题。

    Maven,已经替我们想好了解决方案,就是使用Snapshot版本,在开发过程中B发布的版本标志为Snapshot版本,A进行依赖的时候选择Snapshot版本,那么每次B发布的话,会在私服仓库中,形成带有时间戳的Snapshot版本,而A构建的时候会自动下载B最新时间戳的Snapshot版本!

 

3、pom.xml进行了依赖配置,本地仓库已经下载下来了,为什么还会出现依赖冲突?

    明明已经在pom.xml中进行了依赖配置,检查本地仓库发现依赖包已经存在,却突然提示依赖冲突或某个类找不到。此时可以采取把本地仓库中对应的依赖清空,重新下载即可。

 

4、引入依赖的最佳实践,提前发现问题!

    在项目工程中,我们避免不了不断增加一些依赖,也许加了依赖之后运行时才发现存在依赖冲突再去解决,似乎有点晚!那么能不能提前发现问题呢?

    如果我们新加入一个依赖的话,那么先通过mvn dependency:tree命令形成依赖树,看看我们新加入的依赖,是否存在传递依赖,传递依赖中是否和依赖树中的版本存在冲突,如果存在多个版本冲突,再逐步解决!

 

5、Maven规范化目录结构

上图为Maven项目的规范目录结构。

需要有下面两点注意:

① src/main下内容最终会打包到Jar/War中,而src/test下是测试内容,并不会打包进去。

② src/main/resources中的资源文件会COPY至目标目录,这是Maven的默认生命周期中的一个规定动作。(想一想,hibernate/mybatis的映射XML需要放入resources下,而不能在放在其他地方了)

 

6、Maven的生命周期

如上图所示Maven的生命周期包括:clean、validate、compile、test、package、verify、install、site、deploy,其中需要注意的是:执行后面的命令时,前面的命令自动得到执行,(其中,也可以跳过其中的步骤,如:test)。

  • clean:清理。有问题,多清理!
  • validate:验证。验证项目是否正确。
  • compile:编译。执行编译,源代码编译在此阶段完成。
  • test:测试。使用适当的单元测试框架(例如JUnit)运行测试。
  • package:打包。打成jar 或 war包,其中会自动进行clean+compile。
  • verify:检查。对集成测试的结果进行检查,以保证质量达标。
  • install:安装。将本地工程jar包上传安装到本地仓库,以供其他项目使用。
  • site:站点。进行站点部署。
  • deploy:部署。拷贝最终的工程包到远程仓库或私服中,以共享给其他开发人员和工程。

 

7、关于scope依赖范围

   Maven的生命周期存在编译、测试、打包这些过程,其中有些依赖只是用于测试,如junit,有些依赖编译时是用不到的,只有运行的时候才能用到,比如mysql的驱动包在编译期就用不到(编译期用的是JDBC接口),而是在运行时用到的。还有些依赖,编译期要用到,而运行期不需要提供,因为有些容器已经提供了,比如servlet-api在tomcat中已经提供了,我们只需要的是编译期提供而已。

    其中scope就可以解决上面的问题,即:scope参数用来控制打包的时机,scope有如下几个值,分别代表如下:

  • compile:默认的scope,运行期有效,需要打入包中。
  • provided:编译期有效,运行期不需要提供,不会打入包中。
  • runtime:编译不需要,在运行期有效,需要导入包中。(接口与实现分离)
  • test:测试需要,不会打入包中。
  • system:非本地仓库引入、存在系统的某个路径下的jar。(一般不使用)

 

8、编译时,出现类似“源值1.5已过时,将在未来所有发行版中删除”的错误

在编译项目时,如出现如下类似的错误:

Warning:java: 源值1.5已过时, 将在未来所有发行版中删除
Warning:java: 目标值1.5已过时, 将在未来所有发行版中删除
Warning:java: 要隐藏有关已过时选项的警告, 请使用 -Xlint:-options。

    这是由于在IDEA中使用Maven编译的时候,项目源目标都使用了JDK 1.5的来编译,但是目前我们又没装JDK1.5(实际上我们安装的是JDK1.7以上的版本),最后还是用了我们自己装的版本来编译,因此编译还是不能通过,就出现了刚刚这种错误!
完整解决方法下面三种:

第一种:将IDEA中对应的项目的:【Modules->Language Level】为 ”8”

  • 在IDEA中打开项目设置(或者按下【Ctrl + Alt + Shift + S】)
  • 找到Modules,找到对应的项目
  • 将【Language Level】下拉菜单的值改为 "8"

第二种:配置Maven的配置文件,将编译插件用的JDK改为1.8

  • 打开settings.xml
  • 找到 <profiles>...</profiles> 标签对,并在标签对中间加上如下代码:
<profile>
      <id>jdk-1.8</id>
      <activation>
          <activeByDefault>true</activeByDefault>
          <jdk>1.8</jdk>
      </activation>
      <properties>
          <maven.compiler.source>1.8</maven.compiler.source>
          <maven.compiler.target>1.8</maven.compiler.target>
          <maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
      </properties>
  </profile>
  • 启用该profile设置,找到 <activeProfiles>...</activeProfiles> 标签对,在中间加入:
  <activeProfile>jdk-1.8</activeProfile> 

表示启用该profile的配置。

第三种:在项目的pom.xml中加入

<properties>
   <maven.compiler.source>1.8</maven.compiler.source>
   <maven.compiler.target>1.8</maven.compiler.target>
 </properties>

9、报错“Usage of API documented as @since 1.8+”

  代码中如果出现下面的错误提示:

Usage of API documented as @since 1.8+ 
This inspection finds all usages of methods that have @since tag in their documentation. 
This may be useful when development is performed under newer SDK version as the target platform for production.

    出现该问题的原因是由于我们的代码中使用了JAVA8的新特性,但是Language Level(最低可支持的版本)比较低,无法支持这些特性。比如设置的Language Level为6.0,可是却使用了8.0/9.0的新特性,6.0无法解析这些特性,因此IDE会报错来提醒我们。

在pom.xml中添加如下配置,就可以解决啦。

<build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.6.0</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
</build>

10、Spring Boot、Spring Cloud项目中如何解决各依赖包间相互冲突的问题?

      在微服务项目中,我们会在引入很多依赖包,而且不同依赖包存在很多的版本,经常发现引入的版本不合适,很容易造成一些包中的类相互冲突,如:数据库方面循环调用某个类等,这类问题通常是很难解决的。费好大劲,查询官方网站资料会发现,是由于依赖的某个包的版本不对造成的,你不得不按照要求修改版本号。

     在此, 我告诉大家一个方法可以避免这种问题。可通过Spring Initializr在线(https://start.spring.io/)创建你的项目,从上面可以选择你需要的功能模块,会自动给你匹配对应各个版本,非常方便。你可以不使用它自动生成的demo项目,但可以参考使用它自动生成的pom.xml文件,从中获取对应依赖包的版本。这样就完全可以避免了因选择的版本不对,而造成的一些冲突问题。

 

Maven的爱恨情仇,今天就分享到这里,如果你还遇到过其他问题,可以留言一起谈论分享。

参考:

1.http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html

2.https://www.runoob.com/maven/maven-build-life-cycle.html

3.https://www.cnblogs.com/wangyonghao/p/5976055.html

 

欢迎微信扫码下面二维码,关注微信公众号【程序猿技术大咖】,进行更多交流学习!

展开阅读全文

----------------人生之爱恨情仇---------

04-13

当一个男人在做梦的时候都想到一个女人的身影的时候,这个男人应该是爱上了这个女人,而这个男人如果能得到这个女人的爱,那么这个故事就完美了.如果这个女人不爱这个男人,那么这个男人演出的也不一定就是杯具,但是多半是杯具.爱情也可以演绎成神话的,当爱到达极致的时候,或者还包含着恨.世界上没有无缘无故的爱,也没有无缘无故的恨.然而爱和恨看似对立,却是统一的.当爱到极点时候,容易生恨,当恨到极点的时候,也许正是因为太爱.所以,这个世界,充满着爱恨情仇,如果没有了爱恨情仇,这个世界也就不成其为一个世界了.有了爱和恨,生命才起波澜,人生才有意义.一个人老是生活在自己的小圈子里面,就完全见识不到这个社会的精彩一面.人,必须知道为什么而活,为谁而活.尽管有时候活着是一种痛苦,但是只要迈过前面那道坎,迎接你的将是美好的明天。rn rn 情也是这样,情让人死去活来,轰轰烈烈的爱情已经见怪不怪。更有甚者,为情自杀。所以因情而生爱,因情也能生恨。爱恨情仇再次统一。本身平淡的生活或许会因为一个情字而起风波。多少人因为一个情字难以自拔。对情不负责任的人,不会是好人。太注重情字的人,却又往往会受伤最深。矛盾就此激发。这个时候解药还只能是自己,平和的心态或许才是最佳药方。话说得这么容易,真正能做到却很难。爱恨情仇,真是太过高深,让人摸不透,防不住。那就这样吧,爱就爱了,恨就恨了,顺其自然吧。rnrn 古人云:以其昏昏,使人昭昭。生命其实很精彩。虽然现实中充满着许多无奈,但是我们不能“昏昏”,我们应该勇敢的去面对。只有勇于面对现实的人,才有资格作为这个新时代的胜利者。忘记不快很难,但是时间的流逝会洗刷岁月带来的伤痕。当抚平伤痕以后,抬起头来,继续前行,尽管前面的路满步荆棘,只要你不退缩,总会找到适合自己的路。 论坛

【有奖话题】 说说您与CDN的爱恨情仇

08-10

程序员每天提及的无数词当中,有一个是「CDN」,Ta的中文名是「内容分发网络」,读中文是令人蒙圈的,英文名是Content Delivery Network。文末有科普~rnrn[size=18px]您是在什么样的场景下,怎么来使用CDN呢?[/size]rn我先来个例子: rnrn[quote]我使用了阿里云CDN,为我的网站提供附件的CDN加速,和阿里云OSS配合使用,在降低了存储成本的同时,还降低了流量的费用,让我的网站秒开……[/quote]rn rn当然,有好就有坏,比如 rnrn[quote]我使用了XXXX,虽然免费,虽然不需要备案,然而并没有为我的网站加速,浏览速度反而变慢了……[/quote]rn rn[color=#FF0000][size=18px]我们一起来聊聊[/size][/color]rn您是在什么样的场景下,怎么来使用CDN呢?rn您主要用CDN来解决什么问题呢?大概是怎么用的呢?rn您最难忍受CDN服务哪几点 ?rnrn[size=18px]【参与方式】[/size]rn在8月10日-8月19日期间,参与以上任一话题讨论,写出您的看法,就有机会获得由阿里云提供的奖品rnrn[size=18px][color=#FF0000]【获奖规则】[/color][/size]rn1、来者就有奖,见者就有份——扫码可得rn[align=center] [img=https://img-bbs.csdn.net/upload/201608/10/1470822905_819840.png][/img][/align]rnrn2、回贴,格式为【文章标题】+【链接】rn您的发言越精彩,观点越深刻,讨论越积极,事实清楚,论据充分,就越有机会获赠一张200元阿里云满减代金券。rn名额:[color=#FF0000] 10名[/color]rn小编将根据投稿文章的阅读数、点赞数等,筛选最受欢迎的作者来发放奖品哦~rnrn最终获奖用户将在活动结束后公布在本贴中,届时需要获奖人及时将阿里云帐号私信给小编发奖哦~。活动期间每位用户只能参与一次。rnrn[color=#999999]【最后,普及下CDN知识】rn引用”rnCDN:内容分发网络,对数据提供多节点的分发服务。对于一个文件来说,CDN能够让你的文件存放在世界各地,让你的文件拥有多重分身,在任何地方,都能以最快速度来访问。rnrn我决定以肯德基做为例子,拆解下CDN的几个主要功能:rn(以下原文摘自:http://click.aliyun.com/m/5643/)rnrn肯德基的总部在美国,可是你家楼下也有一家肯德基,并且汉堡包是一模一样的,这就是CDN(这个比喻来自知乎,觉得非常的恰当)。肯德基部署了很多个CDN在世界各地提供服务,用户都是找到最近的店,这个计算过程就是CDN的「就近接入」。rnrn在一个商圈有两家肯德基,有一家组织活动,鸡腿随便吃,所以顾客全部涌到这家店,已经水泄不通,另一家店则门可罗雀。这个时候CDN的调度功能就要发挥作用了,另一家店也发布了一个消息说,买一个汉堡,打五折。这个时候,在第一家店抢不上鸡腿的顾客,马上跑去了第二家店,这个时候两个店的流量处于均衡状态。这就是CDN的「调度」。rnrn美国肯德基总部研发了一个新菜,叫「回锅肉汉堡」,这个时候总部要把这个「内容」向全世界分发,让每一个分店,都能开始卖回锅肉汉堡,好让新老产品能够并驾齐驱,这个就是CDN的「分发」。这个时候你要吃回锅肉汉堡的时候,直接去你家楼下就可以了。rnrn相关推荐:rn这个话题在云栖社区同步火热讨论中,马上查看他们与CDN的爱恨情仇>>rn [url=http://click.aliyun.com/m/5635/]http://click.aliyun.com/m/5635/[/url] rn阿里云 CDN,国内 500+ 节点,海外 30+ 节点,毫秒级响应时间,视频95%+流畅率,了解详情>>[url=http://click.aliyun.com/m/5635/]http://click.aliyun.com/m/5636/[/url][/color] rn 论坛

没有更多推荐了,返回首页