MAVEN简单介绍和使用

概述

maven的主要竞争者是SBT(全称为Simple build tool,是Scala事实上的标准构建工具,随着Scala兴起),曾经红人的Ant(已经确实日薄西山了),Gradle(也许最终将成为MAVEN的终结者)。

依赖:

<dependencies>
    <dependency>
	<groupId>log4j</groupId>
	<artifactId>log4j</artifactId>
	<version>1.2.14</version>
    </dependency>
</dependencies>
  • maven中,如果忽略version设置,会自动下载最新版本。
  • 依赖冲突的调节:如果A->B->C->X(2.0),A->D->X(1.0)。由于只能引入一个版本的包,此时Maven按照最短路径选择导入x(2.0)。如果A->B->X(1.0),A->D->X(2.0)。路径长度一致,则优先选择第一个,此时导入x(1.0)。如果需要指定依赖版本,可以则需要使用exclusion。
  • maven中的仓库分为两种,snapshot快照仓库和release发布仓库。snapshot快照仓库用于保存开发过程中的不稳定版本,release正式仓库则是用来保存稳定的发行版本。定义一个组件/模块为快照版本,只需要在pom文件中在该模块的VERSION后加上-SNAPSHOT即可(注意这里必须是大写)

Maven的scope

1.compile:默认范围,编译测试运行都有效
2.provided:在编译和测试时有效
3.runtime:在测试和运行时有效
4.test:只在测试时有效
5.system:在编译和测试时有效,与本机系统关联,可移植性差
这些scope主要是为了本地环境编译出的代码不会和线上环境相互冲突。

dependencyManagement

<dependencyManagement>
    <dependencies>
        <!-- root-pom 配置 -->
        <dependency>
            <groupId>com.xxx</groupId>
            <artifactId>infra-root-pom</artifactId>
            <version>${root_pom_version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

依赖管理的优先级低于parent中的dependencyManagement中制定的版本。
比如我们最熟悉的

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.6.RELEASE</version>
    </parent>

就实际上采用了spring所推荐的版本。

MAVEN声明周期

Maven定义了三套生命周期:clean、default、site,每个生命周期都包含了一些阶段(phase)。三套生命周期相互独立,但各个生命周期中的phase却是有顺序的,且后面的phase依赖于前面的phase。执行某个phase时,其前面的phase会依顺序执行,但不会触发另外两套生命周期中的任何phase。

clean生命周期

pre-clean :执行清理前的工作;
clean :清理上一次构建生成的所有文件;
post-clean :执行清理后的工作

default生命周期

default生命周期是最核心的,它包含了构建项目时真正需要执行的所有步骤。

validate
initialize
generate-sources
process-sources
generate-resources
process-resources :复制和处理资源文件到target目录,准备打包;
compile :编译项目的源代码;
process-classes
generate-test-sources
process-test-sources
generate-test-resources
process-test-resources
test-compile :编译测试源代码;
process-test-classes
test :运行测试代码;
prepare-package
package :打包成jar或者war或者其他格式的分发包;
pre-integration-test
integration-test
post-integration-test
verify
install :将打好的包安装到本地仓库,供其他项目使用;
deploy :将打好的包安装到远程仓库,供其他项目使用;

site生命周期

pre-site
site :生成项目的站点文档;
post-site
site-deploy :发布生成的站点文档

MAVEN插件

maven插件可以绑定到上述生命周期中执行。比如下面的例子

            <plugin>
                <groupId>io.confluent</groupId>
                <artifactId>kafka-schema-registry-maven-plugin</artifactId>
                <version>4.1.1</version>
                <configuration>
                    <schemaRegistryUrls>
                        <param>http://10.221.198.127:9096</param>
                    </schemaRegistryUrls>
                    <outputDirectory>src/main/resources/avro</outputDirectory>
                    <subjectPatterns>
                        <param>UmeEventTest1</param>
                    </subjectPatterns>
                </configuration>
                <executions>
                    <execution>
                        <phase>initialize</phase>
                        <goals>
                            <goal>download</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.avro</groupId>
                <artifactId>avro-maven-plugin</artifactId>
                <version>1.8.2</version>
                <executions>
                    <execution>
                        <phase>generate-sources</phase>
                        <goals>
                            <goal>schema</goal>
                        </goals>
                        <configuration>
                            <sourceDirectory>${project.basedir}/src/main/resources/avro/</sourceDirectory>
                            <outputDirectory>${project.basedir}/src/main/java/</outputDirectory>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

一个在initialize的phase执行,负责下载文件,一个在generate-sources阶段执行,负责将下载下来的文件改写成java代码。

可选依赖

当一个项目A依赖另一个项目B时,项目A可能很少一部分功能用到了项目B,此时就可以在A中配置对B的可选依赖。举例来说,一个类似hibernate的项目,它支持对mysql、oracle等各种数据库的支持,但是在引用这个项目时,我们可能只用到其对mysql的支持,此时就可以在这个项目中配置可选依赖。

配置可选依赖的原因:1、节约磁盘、内存等空间;2、避免license许可问题;3、避免类路径问题,等等。

示例:

<project>
  ...
  <dependencies>
    <!-- declare the dependency to be set as optional -->
    <dependency>
      <groupId>sample.ProjectB</groupId>
      <artifactId>Project-B</artifactId>
      <version>1.0</version>
      <scope>compile</scope>
      <optional>true</optional> <!-- value will be true or false only -->
    </dependency>
  </dependencies>
</project>

假设以上配置是项目A的配置,即:Project-A --> Project-B。在编译项目A时,是可以正常通过的。

如果有一个新的项目X依赖A,即:Project-X -> Project-A。此时项目X就不会依赖项目B了。如果项目X用到了涉及项目B的功能,那么就需要在pom.xml中重新配置对项目B的依赖。

一些常见的插件的介绍

maven-shade-plugin
  • 将依赖的jar包打包到当前jar包(常规打包是不会将所依赖jar包打进来的);
  • 对依赖的jar包进行重命名(用于类的隔离);
    第一个功能是为了我们减少jar的数量,能够给交付方一个单一的jar显然是最好的。但是会同时带来一个问题,就是jar的重复依赖和冲突。所以,我们可以进行重命名,如下列配置
     <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <version>3.1.1</version>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>shade</goal>
            </goals>
            <configuration>
              <relocations>
                <relocation>
                  <pattern>org.codehaus.plexus.util</pattern>
                  <shadedPattern>org.shaded.plexus.util</shadedPattern>
                  <excludes>
                    <exclude>org.codehaus.plexus.util.xml.Xpp3Dom</exclude>
                    <exclude>org.codehaus.plexus.util.xml.pull.*</exclude>
                  </excludes>
                </relocation>
              </relocations>
            </configuration>
          </execution>
        </executions>
      </plugin>

将将“org.codehaus.plexus.util”重命名为“org.shaded.plexus.util。

profile

在开发过程中,我们的软件会面对不同的运行环境,比如开发环境、测试环境、生产环境,而我们的软件在不同的环境中,有的配置可能会不一样,比如数据源配置、日志文件配置、以及一些软件运行过程中的基本配置,那每次我们将软件部署到不同的环境时,都需要修改相应的配置文件,这样来回修改,很容易出错,而且浪费劳动力。
profile的定义如下

<profiles>
        <profile>
            <id>dev</id>
            <properties>
                <env>dev</env>
            </properties>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
        </profile>
        <profile>
            <id>prd</id>
            <properties>
                <env>prd</env>
            </properties>
        </profile>
    </profiles>

可以理解为,使用profile的机制就是可以动态切换所使用的变量。
常见的使用办法是写在总Pom里,这样可以,像这样

    <profiles>
        <profile>
            <id>dev</id>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
            <repositories>
                <repository>
                ...

这样可以在打不同包时使用不同的repo,使用不同的插件等等。

排查问题

mvn dependency:tree -Dverbose > 1.txt

返回的输出类似

[INFO] +- com.xiaohongshu:event-logging-spring-boot-autoconfigure:jar:0.0.7-SNAPSHOT:compile
[INFO] |  +- org.springframework.boot:spring-boot-autoconfigure:jar:2.1.6.RELEASE:compile
[INFO] |  |  \- (org.springframework.boot:spring-boot:jar:2.1.6.RELEASE:compile - omitted for duplicate)
[INFO] |  \- org.springframework.cloud:spring-cloud-context:jar:2.1.2.RELEASE:compile (version managed from 1.3.1.RELEASE)
[INFO] |     \- org.springframework.security:spring-security-crypto:jar:5.1.5.RELEASE:compile

而不正常的情况下返回

[INFO] +- com.xiaohongshu:event-logging-spring-boot-autoconfigure:jar:0.0.7-SNAPSHOT:compile
[INFO] |  \- org.springframework.boot:spring-boot-autoconfigure:jar:2.1.6.RELEASE:compile
[INFO] |     \- (org.springframework.boot:spring-boot:jar:2.1.6.RELEASE:compile - omitted for duplicate)

可实际上是被exlude掉的

        <dependency>
            <groupId>com.xxx</groupId>
            <artifactId>event-logging-spring-boot-autoconfigure</artifactId>
            <version>0.0.7-SNAPSHOT</version>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>*</artifactId>
                </exclusion>

显然在正常的代码里这部分没有被exluede掉。
可以找到对应的代码

[WARNING] 'dependencies.dependency.exclusions.exclusion.artifactId' for com.xxxx:event-logging-spring-boot-autoconfigure:jar with value '*' does not match a valid id pattern. @ line 282, column 33

实际上这是正常版本过低的问题
https://issues.apache.org/jira/browse/MNG-2315
所以,我们将我们的不正常版本的maven进行降级。就可以解决这个问题。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值