耗时二周,万字总结Maven简明教程,与君共勉!

news2024/11/20 4:23:51

什么是Mavne

Maven 是一个项目管理工具,它包含了一个项目对象模型 (POM:Project Object Model),一组标准集合。由于 Maven 使用标准目录布局和默认构建生命周期,开发团队几乎可以立即自动化项目的构建基础设施。在多个开发团队环境的情况下,Maven 可以在很短的时间内按照标准设置工作方式。

Maven 之前,更多的是使用 Ant 的项目构建工具,Ant 有一个特点,每次都得写,每次都写的差不多,配置也臃肿。所以,后来搞出来 Maven。Maven 就是最先进的版本构建工具吗?不是的,只不过,目前在 Java 领域 Maven 使用比较多。除了 Maven,还有 Gradle。

它的主要功能有:

  • 提供了一套标准化的项目结构;
  • 提供了一套标准化的构建流程(编译,测试,打包,发布……);
  • 提供了一套依赖管理机制。

为了实现上面的主要功能,Maven提供了两大核心:

  • 依赖管理:对 jar 的统一管理(Maven 提供了一个 Maven 的中央仓库,当我们在项目中添加完会自动去中央仓库下载相关的依赖,并且解决依赖的依赖问题)
  • **项目构建:**对项目进行编译、测试、打包、部署、上传到私服等

Maven模型

下面来谈一谈Maven模型的整体结构,包括三个部分:

  • 项目对象模型 (Project Object Model)
  • 依赖管理模型(Dependency)
  • 插件(Plugin)

如上图所示,包括蓝、黄两个部分分别对应着依赖关系和项目构建两大核心功能。

首当其冲的一个核心就是项目对象模型,也就是经常使用的pom.xml

另外一个就是项目构建,Maven的项目构建可以按照生命周期具备以下三个标准生命周期:

  • clean:项目清理的处理
  • default(或 build):项目部署的处理
  • site:项目站点文档创建的处理

项目对象模型(POM)

POM 代表项目对象模型。它是 Maven 中的基本工作单元。它是一个 XML 文件,作为 pom.xml 驻留在项目的跟目录中。POM 不仅包含有关项目的信息以及 Maven 用于构建项目的各种配置详细信息, 还包含目标和插件。

在执行任务或目标时,Maven 在当前目录中查找 POM。它读取 POM,获取所需的配置信息,然后执行目标。在POM文件中常见的配置包括一下几点:

  • 项目依赖
  • 插件
  • 目标
  • 建立档案
  • 项目版本
  • 开发商
  • 邮件列表

在创建 POM 之前,我们应该首先确定项目(groupId)、项目名称(artifactId) 和版本,因为这些属性有助于在存储库中唯一标识项目。

<project xmlns = "http://maven.apache.org/POM/4.0.0"
   xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation = "http://maven.apache.org/POM/4.0.0
   http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.coderV</groupId>
    <artifactId>coderV</artifactId>
    <packaging>jar</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>com.coderV</name>
    <url>http://maven.apache.org</url>
    <dependencies>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>5.8.2</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
            //...
            </plugin>
        </plugins>
    </build>
</project>
复制代码

接下来仔细拆解POM文件结构

1、项目标识符

Maven 使用一组标识符(也称为坐标)来唯一标识项目并指定应如何打包项目工件:

  • groupId: 创建项目的公司或组的唯一基本名称
  • artifactId: 项目的唯一名称
  • **version:**项目的一个版本
  • packaging: 一种打包方法(例如WAR / JAR / ZIP

其中所有 POM 文件都需要项目元素和三个必填字段:groupId、artifactId、version

其中的前三个 ( groupId:artifactId:version ) 结合形成唯一标识符,并且是您指定项目将使用的外部库(例如 JAR)版本的机制。

详细说明一些基本的项目标识符6

参数名称描述
Project root这是项目root的标签。您需要指定基本架构设置,例如 apache 架构和 w3.org 规范。
Model version模型版本应为 4.0.0。
**groupId **这是项目组/公司的 ID。这在组织或项目中通常是唯一的。
artifactId这是项目的 ID。这通常是项目的名称
version这是项目的版本

2、依赖管理

Maven 使用存储库的概念进行依赖管理,项目中使用的这些外部库称为依赖项。Maven 中的依赖项管理功能可确保从中央存储库自动下载这些库,因此您不必将它们存储在本地。

这是 Maven 的一个关键特性,并提供以下好处:

  • 结合本地仓库大幅减少从远程存储库下载的数量,减少存储使用量
  • 管理项目依赖性变得更容易
  • 提供了一个有效的平台,用于在组织内外交换二进制组件,而无需每次都从源代码手动安装组件

为了声明对外部库的依赖,您需要提供库的groupId、artifactId、verison。让我们看一个例子:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>5.3.16</version>
</dependency>
复制代码

当 Maven 处理依赖项时,它会将 Spring Core 库下载到本地 Maven 存储库中,并在项目中使用

传递依赖

如下图所示,项目 A 依赖于项目 B,B 又依赖于项目 C,此时 B 是 A 的直接依赖,C 是 A 的间接依赖

Maven 的依赖传递机制是指:不管 Maven 项目存在多少间接依赖,POM 中都只需要定义其直接依赖,不必定义任何间接依赖,Maven 会动读取当前项目各个直接依赖的 POM,将那些必要的间接依赖以传递性依赖的形式引入到当前项目中。Maven 的依赖传递机制能够帮助用户一定程度上简化 POM 的配置。

基于 A、B、C 三者的依赖关系,根据 Maven 的依赖传递机制,我们只需要在项目 A 的 POM 中定义其直接依赖 B,在项目 B 的 POM 中定义其直接依赖 C,Maven 会解析 A 的直接依赖 B的 POM ,将间接依赖 C 以传递性依赖的形式引入到项目 A 中。

通过这种依赖传递关系,可以使依赖关系树迅速增长到一个很大的量级,很有可能会出现依赖重复,依赖冲突等情况,Maven 针对这些情况提供了如下功能进行处理。

  • 依赖范围(Dependency scope)
  • 依赖调解(Dependency mediation)
  • 可选依赖(Optional dependencies)
  • 排除依赖(Excluded dependencies)
  • 依赖管理(Dependency management)

Maven 具有以下 6 中常见的依赖范围,如下表所示。

依赖范围描述
compile编译依赖范围,scope 元素的缺省值。使用此依赖范围的 Maven 依赖,对于三种 classpath 均有效,即该 Maven 依赖在上述三种 classpath 均会被引入。例如,log4j 在编译、测试、运行过程都是必须的。
test测试依赖范围。使用此依赖范围的 Maven 依赖,只对测试 classpath 有效。例如,Junit 依赖只有在测试阶段才需要。
provided已提供依赖范围。使用此依赖范围的 Maven 依赖,只对编译 classpath 和测试 classpath 有效。例如,servlet-api 依赖对于编译、测试阶段而言是需要的,但是运行阶段,由于外部容器已经提供,故不需要 Maven 重复引入该依赖。
runtime运行时依赖范围。使用此依赖范围的 Maven 依赖,只对测试 classpath、运行 classpath 有效。例如,JDBC 驱动实现依赖,其在编译时只需 JDK 提供的 JDBC 接口即可,只有测试、运行阶段才需要实现了 JDBC 接口的驱动。
system系统依赖范围,其效果与 provided 的依赖范围一致。其用于添加非 Maven 仓库的本地依赖,通过依赖元素 dependency 中的 systemPath 元素指定本地依赖的路径。鉴于使用其会导致项目的可移植性降低,一般不推荐使用。
import导入依赖范围,该依赖范围只能与 dependencyManagement 元素配合使用,其功能是将目标 pom.xml 文件中 dependencyManagement 的配置导入合并到当前 pom.xml 的 dependencyManagement 中。

依赖范围与三种 classpath 的关系一览表,如下所示。

依赖范围编译 classpath测试 classpath运行 classpath例子
compilelog4j
test--junit
provided-servlet-api
runtime--JDBC-driver
system-非 Maven 仓库的本地依赖

依赖范围对传递依赖的影响

项目 A 依赖于项目 B,B 又依赖于项目 C,此时我们可以将 A 对于 B 的依赖称之为第一直接依赖,B 对于 C 的依赖称之为第二直接依赖。

B 是 A 的直接依赖,C 是 A 的间接依赖,根据 Maven 的依赖传递机制,间接依赖 C 会以传递性依赖的形式引入到 A 中,但这种引入并不是无条件的,它会受到依赖范围的影响。

传递性依赖的依赖范围受第一直接依赖和第二直接依赖的范围影响,如下表所示。

compiletestprovidedruntime
compilecompile--runtime
testtest--test
providedprovided-providedprovided
runtimeruntime--runtime

注:上表中,左边第一列表示第一直接依赖的依赖范围,上边第一行表示第二直接依赖的依赖范围。交叉部分的单元格的取值为传递性依赖的依赖范围,若交叉单元格取值为“-”,则表示该传递性依赖不能被传递。

通过上表,可以总结出以下规律(*):

  • 当第二直接依赖的范围是 compile 时,传递性依赖的范围与第一直接依赖的范围一致;
  • 当第二直接依赖的范围是 test 时,传递性依赖不会被传递;
  • 当第二直接依赖的范围是 provided 时,只传递第一直接依赖的范围也为 provided 的依赖,且传递性依赖的范围也为 provided;
  • 当第二直接依赖的范围是 runtime 时,传递性依赖的范围与第一直接依赖的范围一致,但 compile 例外,此时传递性依赖的范围为 runtime。

依赖调节

Maven 的依赖传递机制可以简化依赖的声明,用户只需要关心项目的直接依赖,而不必关心这些直接依赖会引入哪些间接依赖了。为了避免出现依赖重复的问题,Maven 通过依赖调节来确定间接依赖的引入路径。

依赖调节遵循以下两条原则:

  1. 引入路径短者优先
  2. 先声明者优先

引入路径短者优先

引入路径短者优先,顾名思义,当一个间接依赖存在多条引入路径时,引入路径短的会被解析使用。

例如,A 存在这样的依赖关系: A->B->C->D(1.0) A->X->D(2.0)

D 是 A 的间接依赖,但两条引入路径上有两个不同的版本,很显然不能同时引入,否则造成重复依赖的问题。根据 Maven 依赖调节的第一个原则:引入路径短者优先,D(1.0)的路径长度为 3,D(2.0)的路径长度为 2,因此间接依赖 D(2.0)将从 A->X->D(2.0) 路径引入到 A 中。

先声明者优先

先声明者优先,顾名思义,在引入路径长度相同的前提下,POM 文件中依赖声明的顺序决定了间接依赖会不会被解析使用,顺序靠前的优先使用。

例如,A 存在以下依赖关系: A->B->D(1.0) A->X->D(2.0)

D 是 A 的间接依赖,其两条引入路径的长度都是 2,此时 Maven 依赖调节的第一原则已经无法解决,需要使用第二原则:先声明者优先。

Maven排除依赖和可选依赖

我们知道 Maven 依赖具有传递性,例如 A 依赖于 B,B 依赖于 C,在不考虑依赖范围等因素的情况下,Maven 会根据依赖传递机制,将间接依赖 C 引入到 A 中。但如果 A 出于某种原因,希望将间接依赖 C 排除,那该怎么办呢?Maven 为用户提供了两种解决方式:排除依赖(Dependency Exclusions)和可选依赖(Optional Dependencies)。

排除依赖

假设存在这样的依赖关系,A 依赖于 B,B 依赖于 X,B 又依赖于 Y。B 实现了两个特性,其中一个特性依赖于 X,另一个特性依赖于 Y,且两个特性是互斥的关系,用户无法同时使用两个特性,所以 A 需要排除 X,此时就可以在 A 中将间接依赖 X 排除。

排除依赖是通过在 A 中使用 exclusions 元素实现的,该元素下可以包含若干个 exclusion 子元素,用于排除若干个间接依赖,示例代码如下:

    <dependencies>
        <dependency>
            <groupId>net.biancheng.www</groupId>
            <artifactId>B</artifactId>
            <version>1.0-SNAPSHOT</version>
            <exclusions>
                <!-- 设置排除 -->
                <!-- 排除依赖必须基于直接依赖中的间接依赖设置为可以依赖为 false -->
                <!-- 设置当前依赖中是否使用间接依赖 -->
                <exclusion>
                    <!--设置具体排除-->
                    <groupId>net.biancheng.www</groupId>
                    <artifactId>X</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>
复制代码

关于 exclusions 元素及排除依赖说明如下:

  • 排除依赖是控制当前项目是否使用其直接依赖传递下来的间接依赖;
  • exclusions 元素下可以包含若干个 exclusion 子元素,用于排除若干个间接依赖;
  • exclusion 元素用来设置具体排除的间接依赖,该元素包含两个子元素:groupId 和 artifactId,用来确定需要排除的间接依赖的坐标信息;
  • exclusion 元素中只需要设置 groupId 和 artifactId 就可以确定需要排除的依赖,无需指定版本 version。

可选依赖

与上文的应用场景相同,也是 A 希望排除间接依赖 X,除了在 B 中设置可选依赖外,我们还可以在 B 中将 X 设置为可选依赖。

设置可选依赖

在 B 的 POM 关于 X 的依赖声明中使用 optional 元素,将其设置成可选依赖,示例配置如下:

    <dependencies>
        <dependency>
            <groupId>net.biancheng.www</groupId>
            <artifactId>X</artifactId>
            <version>1.0-SNAPSHOT</version>
            <!--设置可选依赖  -->
            <optional>true</optional>
        </dependency>
    </dependencies>
复制代码

关于 optional 元素及可选依赖说明如下:

  • 可选依赖用来控制当前依赖是否向下传递成为间接依赖;
  • optional 默认值为 false,表示可以向下传递称为间接依赖;
  • 若 optional 元素取值为 true,则表示当前依赖不能向下传递成为间接依赖。

排除依赖 VS 可选依赖

排除依赖和可选依赖都能在项目中将间接依赖排除在外,但两者实现机制却完全不一样。

    • 排除依赖是控制当前项目是否使用其直接依赖传递下来的接间依赖;
    • 可选依赖是控制当前项目的依赖是否向下传递;
    • 可选依赖的优先级高于排除依赖;
    • 若对于同一个间接依赖同时使用排除依赖和可选依赖进行设置,那么可选依赖的取值必须为 false,否则排除依赖无法生效。

3、Maven 仓库

在 Maven 术语中,仓库是存储所有项目的 jar包的地方,Maven 可以轻松使用它们。根据类别可以将Maven仓库分为三类:

1)本地仓库 默认情况下,每个本地计算机的用户目录下都有一个路径名为.m2/repository/的仓库目录,这个就是本地的仓库

也可以在 settings.xml 文件配置本地仓库的路径

2)远程仓库 远程仓库也称为私服,由公司或者项目组维护,是开发人员自己定义的远程仓库,其中包含项目所需要的库或其他的jar包,可以通过标签来制定远程仓库地址

   <repositories>
      <repository>
         <id>companyname.lib1</id>
         <url>http://download.companyname.org/maven2/lib1</url>
      </repository>
   </repositories>
复制代码

3)中央仓库

Maven中央仓库是Maven社区提供的仓库。它包含大量常用的库。当 Maven 在本地存储库中找不到任何依赖项时,就会从中央仓库中搜索

其中中央仓库有以下几点需要注意:

  • 此存储库由 Maven 社区管理。
  • 不需要配置,但可以替换中央仓库的源为制定的镜像源
  • 它需要互联网访问才能搜索。

Maven 依赖加载顺序

当我们执行 Maven 构建命令时,Maven 开始按以下顺序查找依赖库:

  • 第 1 步- 在本地存储库中搜索依赖项,如果未找到,则转到第 2 步,否则执行进一步处理。
  • 第 2 步- 如果没有提到远程存储库,则跳转到第 3 步。在一个或多个远程存储库中搜索依赖项,如果找到则将其下载到本地存储库以供将来参考
  • 第 3 步- 在中央存储库中搜索依赖项,将其下载到本地存储库以供将来参考。如果未找到 Maven 只是停止处理并抛出错误(无法找到依赖项)

4、属性(properties)

自定义属性有助于pom.xml文件更易于阅读和维护。一个十分经典的使用场景就是,通过自定义属性来定义项目依赖项的版本。

Mavenproperties是一个占位符,通过properties定义不同属性名的值

例如下面的例子中,通过<properties>定义了一个spring.version的属性,其具体的值为 5.3.16;如果想要将 Spring 升级到更新的版本,就只需更改<spring.version>属性标签内的值,所有在其<version>标签中使用该属性的依赖项都将更新。

<properties>
    <spring.version>5.3.16</spring.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>${spring.version}</version>
    </dependency>
</dependencies>
复制代码

另一个常用的场景就是使用<properties>定义构建路径的变量,例如

<properties>
    <project.build.folder>${project.build.directory}/tmp/</project.build.folder>
</properties>

<plugin>
    //...
    <outputDirectory>${project.resources.build.folder}</outputDirectory>
    //...
</plugin>
复制代码

5、Build

build部分也是 Maven POM 中非常重要的部分。它提供有关默认 Maven目标、已编译项目的目录和应用程序的最终名称的信息。默认build如下所示:

<build>
  	<!--当项目没有规定目标(Maven2叫做阶段(phase))时的默认值, -->
		<!--必须跟命令行上的参数相同例如jar:jar,或者与某个阶段(phase)相同例如install、compile等 -->
    <defaultGoal>install</defaultGoal>
  	<!-- 构建产生的所有文件存放的目录,默认为${basedir}/target,即项目根目录下的target -->
    <directory>${basedir}/target</directory>
  	<!-- 产生的构件的文件名,默认值是${artifactId}-${version}-->
    <finalName>${artifactId}-${version}</finalName>
 	  <!--当filtering开关打开时,使用到的过滤器属性文件列表。 -->
		<!--项目配置信息中诸如${spring.version}之类的占位符会被属性文件中的实际值替换掉 -->
    <filters>
      <filter>filters/filter1.properties</filter>
    </filters>
    //...
</build>
复制代码

编译工件的默认输出文件夹名为*target*,打包工件的最终名称由*artifactId*和*version*组成,但您可以随时更改。

6、配置文件

构建配置文件是一组配置值,可用于设置或覆盖 Maven 构建的默认值。使用构建配置文件,您可以为不同的环境(例如生产环境和开发环境)自定义构建。

配置文件主要分为两种类型,一种是在定义在项目上pom.xml文件中,另一种是定义在setting.xml上

<profiles>
    <profile>
        <id>production</id>
        <build>
            <plugins>
                <plugin>
                //...
                </plugin>
            </plugins>
        </build>
    </profile>
    <profile>
        <id>development</id>
        <activation>
            <activeByDefault>true</activeByDefault>
        </activation>
        <build>
            <plugins>
                <plugin>
                //...
                </plugin>
            </plugins>
        </build>
     </profile>
 </profiles>
复制代码

定义在pom.xml文件上的profile可以看做pom.xml的副本,拥有与pom.xml相同的子元素与配置方法。

正如您在上面的示例中看到的,默认配置文件设置为development。如果要运行生产配置文件,可以使用以下 Maven 的 -P 命令显示的激活一个profile:

mvn clean install -P production
复制代码

Maven 构建生命周期

每个 Maven 构建都遵循指定的生命周期。您可以执行多个构建生命周期目标,包括编译项目代码、创建包以及在本地 Maven 依赖项存储库中安装存档文件的目标。

以下列表显示了最重要的 Maven生命周期阶段:

  • validate: 检查项目的正确性
  • compile: 将提供的源代码编译成二进制工件
  • test: 执行单元测试
  • package: 将编译后的代码打包*到归档文件中
  • integration-test: 执行额外的测试,这需要打包
  • verify——检查包是否有效
  • install – 将包文件安装到本地 Maven 存储库
  • deploy – 将包文件部署到远程服务器或存储库

1、Clean 生命周期

当我们执行 mvn post-clean 命令时,Maven 调用 clean 生命周期,它包含以下阶段:

  • pre-clean:执行一些需要在clean之前完成的工作
  • clean:移除所有上一次构建生成的文件
  • post-clean:执行一些需要在clean之后立刻完成的工作

在一个生命周期中,运行某个阶段的时候,它之前的所有阶段都会被运行,也就是说,如果执行 mvn clean 将运行pre-clean, clean两个生命周期阶段;运行 mvn post-clean ,则运行pre-clean, clean, post-clean三个生命周期阶段

2、Default (Build) 生命周期

这是 Maven 的主要生命周期,被用于构建应用,包括下面的 23 个阶段:

生命周期阶段描述
validate(校验)校验项目是否正确并且所有必要的信息可以完成项目的构建过程。
initialize(初始化)初始化构建状态,比如设置属性值。
generate-sources(生成源代码)生成包含在编译阶段中的任何源代码。
process-sources(处理源代码)处理源代码,比如说,过滤任意值。
generate-resources(生成资源文件)生成将会包含在项目包中的资源文件。
process-resources (处理资源文件)复制和处理资源到目标目录,为打包阶段最好准备。
compile(编译)编译项目的源代码。
process-classes(处理类文件)处理编译生成的文件,比如说对Java class文件做字节码改善优化。
generate-test-sources(生成测试源代码)生成包含在编译阶段中的任何测试源代码。
process-test-sources(处理测试源代码)处理测试源代码,比如说,过滤任意值。
generate-test-resources(生成测试资源文件)为测试创建资源文件。
process-test-resources(处理测试资源文件)复制和处理测试资源到目标目录。
test-compile(编译测试源码)编译测试源代码到测试目标目录.
process-test-classes(处理测试类文件)处理测试源码编译生成的文件。
test(测试)使用合适的单元测试框架运行测试(Juint是其中之一)。
prepare-package(准备打包)在实际打包之前,执行任何的必要的操作为打包做准备。
package(打包)将编译后的代码打包成可分发格式的文件,比如JAR、WAR或者EAR文件。
pre-integration-test(集成测试前)在执行集成测试前进行必要的动作。比如说,搭建需要的环境。
integration-test(集成测试)处理和部署项目到可以运行集成测试环境中。
post-integration-test(集成测试后)在执行集成测试完成后进行必要的动作。比如说,清理集成测试环境。
verify (验证)运行任意的检查来验证项目包有效且达到质量标准。
install(安装)安装项目包到本地仓库,这样项目包可以用作其他本地项目的依赖。
deploy(部署)将最终的项目包复制到远程仓库中与其他开发者和项目共享。

Site 生命周期

Maven Site 插件一般用来创建新的报告文档、部署站点等。

  • pre-site:执行一些需要在生成站点文档之前完成的工作
  • site:生成项目的站点文档
  • post-site: 执行一些需要在生成站点文档之后完成的工作,并且为部署做准备
  • site-deploy:将生成的站点文档部署到特定的服务器上

插件(Plugin)

插件管理与依赖管理原理一样、不同的是定义的元素标签不一样、插件管理标签是build标签的子标签pluginManagement

pluginManagement 用来做插件管理的。它是表示插件声明,即你在项目中的pluginManagement下声明了插件,Maven不会加载该插件,pluginManagement声明可以被继承。如下面的例子

<pluginManagement>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-source-plugin</artifactId>
            <version>2.1</version>
            <configuration>
                <attach>true</attach>
            </configuration>
            <executions>
                <execution>
                    <phase>compile</phase>
                    <goals>
                        <goal>jar</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</pluginManagement>

<!-- 子POM-->
<plugins>
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-source-plugin</artifactId>
    </plugin>
</plugins>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/112254.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

代码随想录训练营第60天|LeetCode 84.柱状图中最大的矩形

LeetCode 84.柱状图中最大的矩形 双指针 注意&#xff0c;双指针解法可行&#xff0c;但是在力扣上提交会超时。 以heights[i]为中心&#xff0c;用两个指针向两边扩散&#xff0c;直到heights[left]和heights[right]小于heights[i]为止&#xff0c;这样就构成了以left和rig…

第11章_数据库的设计规范(理论了解)

第11章_数据库的设计规范 范式 2.3键和相关属性的概念 范式的定义会使用到主键和候选键&#xff0c;数据库中的键(Key)由一个或者多个属性组成。数据表中常用的几种键和属性的定义: 超键︰能唯─标识元组的属性集叫做超键。候选键︰如果超键不包括多余的属性&#xff0c;那…

基于HOG+LBP完成特征工程,基于机器学习模型同时完成人脸识别+表情识别

这周前两天有时间我写了一篇博文&#xff0c;基于LBP和HOG实现人脸好表情特征的提取计算&#xff0c;之后分别训练了人脸识别模型和表情识别模型&#xff0c;在推理阶段实现了单张图像一次性人脸识别和表情识别的计算分析&#xff0c;但这个我前面就说了这个还是间接的实现方式…

关于GC原理和性能调优实践,看这一篇就够了

前言 本文介绍 GC 基础原理和理论&#xff0c;GC 调优方法思路和方法&#xff0c;基于 Hotspot jdk1.8&#xff0c;学习之后你将了解如何对生产系统出现的 GC 问题进行排查解决。 正文 本文的内容主要如下&#xff1a; GC 基础原理&#xff0c;涉及调优目标&#xff0c;GC 事…

Redis原理篇—数据结构

Redis原理篇—数据结构 笔记整理自 b站_黑马程序员Redis入门到实战教程 底层数据结构 动态字符串SDS 我们都知道 Redis 中保存的 Key 是字符串&#xff0c;value 往往是字符串或者字符串的集合。可见字符串是 Redis 中最常用的一种数据结构。 不过 Redis 没有直接使用C语言中…

Python圣诞树

目录 一、前言 二、创意名 三、效果展示 四、实现步骤 五、编码实现 一、前言 一年一度的圣诞节又要来喽~在这么浪漫的节日里怎么能少的了一个浪漫的程序员呢~让我们一起画个圣诞树&#xff0c;送给你喜欢的那个人吧~ 二、创意名 Python浪漫圣诞树&#xff0c;具体源码见&…

嘿ChatGPT,来帮我写代码

最近 ChatGPT 发行了&#xff0c;这是由 OpenAI 开发的AI聊天机器人&#xff0c;专门研究对话。它的目标是使AI系统更自然地与之互动&#xff0c;但是在编写代码时也可以为您提供帮助。您可以让 ChatGPT 做你的编程助理&#xff0c;甚至更多&#xff01;在过去的几天里&#xf…

腾讯云轻量应用服务器使用 SRS 应用镜像搭建个人直播间、视频转播、本地录制!

SRS 是一个开源的流媒体集群&#xff0c;主要应用在直播和 WebRTC&#xff0c;支持 RTMP、WebRTC、HLS、HTTP-FLV 和 SRT 等常用协议。 轻量应用服务器提供了 SRS 应用镜像&#xff0c;使您无需再关注繁杂的部署操作&#xff0c;即可通过该镜像在轻量应用服务器上一键搭建个人…

安卓/华为手机恢复出厂设置后如何恢复照片

绝大多数安卓用户都会经历过手机恢复出厂设置&#xff0c;部分用户可能没有意识到手机恢复出厂设置可能会导致数据丢失。但是&#xff0c;当您在 云盘上进行备份或在设备上进行本地备份时&#xff0c;情况就会有所不同&#xff0c;并且当您将 安卓手机恢复出厂设置时&#xff0…

LeetCode HOT 100 —— 581. 最短无序连续子数组

题目 给你一个整数数组 nums &#xff0c;你需要找出一个 连续子数组 &#xff0c;如果对这个子数组进行升序排序&#xff0c;那么整个数组都会变为升序排序。 请你找出符合题意的 最短 子数组&#xff0c;并输出它的长度。 思路 方法一&#xff1a;双指针 排序 最终目的是让…

大气湍流自适应光学校正算法matlab仿真,包括涡旋光束,大气湍流影响,不同轨道角动量OAM态之间的串扰,校正等

目录 1.算法描述 2.仿真效果预览 3.MATLAB核心程序 4.完整MATLAB 1.算法描述 涡旋光束是一种具有螺旋波前的光束&#xff0c;在涡旋光束中&#xff0c;决定涡旋光束特性的角量子数可以是任意一个自然数&#xff0c;其不同设置所产生的涡旋光束之间存在正交关系。目前&#…

Android NDK 中堆栈日志 add2line 的分析实践

文章目录目的常用的辅助工具分析步骤参考目的 Android NDK 中出现的 crash 日志分析定位&#xff0c;使用 addr2line 对库中定位so 动态库崩溃位置&#xff0c;定位到某个函数的具体的代码行。 常用的辅助工具 add2line&#xff0c;objdump&#xff0c;ndkstack 等等。本文主要…

一文深度揭开Redis的磁盘持久化机制

前言 Redis 是内存数据库&#xff0c;数据都是存储在内存中&#xff0c;为了避免进程退出导致数据的永久丢失&#xff0c;需要定期将 Redis 中的数据以数据或命令的形式从内存保存到本地磁盘。当下次 Redis 重启时&#xff0c;利用持久化文件进行数据恢复。Redis 提供了 RDB 和…

在linux上安装并初始化配置MariaDB支持远程登录

在linux上安装并初始化配置MariaDB支持远程登录一、环境准备二、启动MariaDB三、初始化MariaDB四、配置远程访问五、补充一些额外的MySql用户赋权限的语句一、环境准备 本文环境是Redhat7上自带的MariaDB, 在安装redhat系统时已经自动安装好了&#xff0c;如果需要自行安装的话…

Selenium 常用函数总结

Seleninum作为自动化测试的工具&#xff0c;自然是提供了很多自动化操作的函数&#xff0c; 下面列举下个人觉得比较常用的函数&#xff0c;更多可见官方文档&#xff1a; 官方API文档&#xff1a; http://seleniumhq.github.io/selenium/docs/api/py/api.html 1) 定位元素 f…

【源码共读】axios的46个工具函数

所有工具函数 还是老样子&#xff0c;先看看axios的工具函数有哪些&#xff0c;先心里有个印象&#xff0c;然后再逐个分析。 直接拉到最下面&#xff0c;可以看到axios的工具函数都是统一导出的&#xff1a; export default {isArray, // 判断是否是数组isArrayBuffer, // …

[机缘参悟-95] :不同人生和社会问题的本质

事情的本质是物极必反&#xff08;轮回、周期&#xff09; 社会的本质是优胜劣汰&#xff08;迭代、发展&#xff09; 道德的本质是伦理秩序&#xff08;未定、秩序&#xff09; 战争的本质是资源占用&#xff08;弱肉、强食&#xff09; 商业的本质是价值交换 金钱的本质…

同事这样用Redis,把我害惨了

首先说下问题现象&#xff1a;内网sandbox环境API持续1周出现应用卡死&#xff0c;所有api无响应现象 刚开始当测试抱怨环境响应慢的时候 &#xff0c;我们重启一下应用&#xff0c;应用恢复正常&#xff0c;于是没做处理。但是后来问题出现频率越来越频繁&#xff0c;越来越多…

MySQL实现主从复制(Windows)的明细操作步骤

文章目录一、教学视频地址二、设计思路三、具体步骤一、教学视频地址 视频地址&#xff1a;视频链接 二、设计思路 准备两个5.7版本的MySQL&#xff0c;一个用作主数据库&#xff0c;另一个用作从数据库。 把主数据库做为写入数据库&#xff0c;从数据库作为读数据库。 三…

【云原生 Kubernetes】基于 KubeAdmin 搭建k8s集群

一、前言 在上一篇&#xff0c;我们基于minikube搭建了一个单节点的k8s集群&#xff0c;作为学习和练习使用的话问题不大&#xff0c;但如果想深入学习和了解k8s的相关技术体系&#xff0c;还是需要搭建真正的集群才能更接近生产环境的应用&#xff0c;本篇将基于KubeAdmin&…