This is the 9th day of my participation in the November Gwen Challenge. Check out the event details: The last Gwen Challenge 2021
reading
Take a fresh look at Maven as a tool
The Maven project goes from 0 to 1
preface
Dependency management is a core feature of Maven, and it is the one we use most. For developers, it may not be necessary to package deployment with Maven, but it is difficult to avoid adding or removing dependencies.
Before Maven or a similar build tool, managing the dependencies of a single project was relatively simple, but managing the dependencies of multi-module projects and applications made up of hundreds of modules was quite complex, and Maven came along in part to solve this problem.
Depend on the transfer
If your project depends on a dependency, such as ABC, which itself depends on XYZ, then your project also depends on XYZ. This feature is called dependency passing.
There is no limit to how many levels of dependency can be passed, and it is only in the case of circular dependencies that problems arise.
Cyclic dependencies are those in which A depends on B, and B depends on C. If A is added to project C, A cyclic dependency is formed.
Maven has special mechanisms to address the problems that arise because of the dependency passing feature.
Dependency mediation: Dependency mediation is the mechanism of choice when there are multiple versions of dependencies or transitive dependencies under a project. Maven uses the “nearest rule” for selection, as in the following case:
A │ ├── B │ ├── C │ ├─ D │ ├─Copy the code
There are two dependency lines A->B->C->D2.0 and A->E->D1.0 in project A, so D1.0 will be used as A dependency in project A construction, because D1.0 is closer to project A than D2.0.
If two dependencies are the same distance apart, the dependency defined earlier is used first.
It is also possible to display the version of the specified dependency in the A project, such as the D2.0 version used in the following example:
A ├ ─ ─ B │ └ ─ ─ C │ └ ─ ─ D 2.0 └ ─ ─ E │ └ ─ ─ D 1.0 └ ─ ─ D 2.0Copy the code
DependencyManagement: You can specify the version of a dependency in DependencyManagement. For a specified dependency, the version will be used directly when a transfer dependency is encountered. In the previous example we added D2.0 directly to A dependency. We can also specify the version of the D dependency directly in DependencyManagement.
Dependency Scope: You can specify in which build phase a dependency will be used, described separately later.
Dependency Exclusion: If Project X is dependent on project Y and project Y is dependent on Project Z, then project X can explicitly exclude project Z using the Exclusion element.
Optional dependencies: If item Y depends on item Z, item Y can mark item Z as an optional dependency using the optional element. When item X depends on item Y, X will depend only on Y and not on the optional dependency Z of Y. Project X can add dependencies on Z as it chooses.
Although Maven has rely on transmission characteristics, but we should specify the dependencies we need version, such as when our project A relies on B, B is dependent on the C, if we are not in A specified directly C version, when B to C version changes, are likely to cause A build our project failure.
Depends on scope scope
The dependency scope is used to limit the transitivity of dependencies and determine at what stage a dependency takes effect.
There are six scope options in Maven:
compile
This is the default scope. Representation is available at all phases, and dependencies are propagated to dependent projects.
provided
You want the JDK or container to provide dependencies at run time. For example, when JavaEE builds a Web application, the dependency scope of the Servlet API and related JavaEE APIS is set to Provided because these classes are already provided in the Web container. Dependencies with this scope are added to the classpath for compilation and testing, not the runtime classpath. It’s not transitive.
runtime
This dependency is not required for compilation, but is required at runtime. Maven contains dependencies for this scope at run time and in the test classpath.
test
This scope indicates that the dependency is not required for proper use of the application and is only available during the test compilation and execution phases. This range is not transitive. Typically, this scope is used for test libraries such as JUnit and Mockito. That is, dependencies that are not used in SRC /main/ Java can use this scope if they are only used in SRC /test/ Java.
system
This scope is similar to the provided scope, except that the JAR files are supplied directly and are not searched in the repository at build time.
import
This scope differs from the others in that it is only supported for a
node whose type node is POM.
<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.heiz</groupId>
<artifactId>hello-world-scope</artifactId>
<packaging>pom</packaging>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.heiz</groupId>
<artifactId>hello-world-package</artifactId>
<version>1.0.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>18.0</version>
</dependency>
</dependencies>
<dependencyManagement>
</project>
Copy the code
The implication of this configuration is that, in the current project, the dependencies from the Hello-world-package project are introduced into the current project, similar to an inclusion import of configuration information.
DependencyManagement
The role of DependencyManagement can be summarized as follows:
- Unified management of common dependencies simplifies subproject configuration
- Control transitive dependency version selection for dependent items
Here are two examples of these effects.
Example: Simplify subproject configuration
Dependencies in project A
<project>.<dependencies>
<dependency>
<groupId>group-a</groupId>
<artifactId>artifact-b</artifactId>
<version>1.0</version>
<type>bar</type>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>groupId-a</groupId>
<artifactId>artifact-a</artifactId>
<version>1.0</version>
<exclusions>
<exclusion>
<groupId>group-c</groupId>
<artifactId>artifact-c</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</project>
Copy the code
Dependencies in project B
<project>.<dependencies>
<dependency>
<groupId>group-a</groupId>
<artifactId>artifact-b</artifactId>
<version>1.0</version>
<type>bar</type>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>groupId-a</groupId>
<artifactId>artifact-c</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
</project>
Copy the code
Project A and project B have A common dependency, and each has A unique dependency. This information can be extracted into the DependencyManagement in the parent POM:
<project>.<dependencyManagement>
<dependencies>
<dependency>
<groupId>groupId-a</groupId>
<artifactId>artifact-a</artifactId>
<version>1.0</version>
<exclusions>
<exclusion>
<groupId>group-c</groupId>
<artifactId>artifact-c</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>group-a</groupId>
<artifactId>artifact-b</artifactId>
<version>1.0</version>
<type>bar</type>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>groupId-a</groupId>
<artifactId>artifact-c</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
Copy the code
Then the POM in the A and B subprojects becomes very simple:
The project a.
<project>.<dependencies>
<dependency>
<groupId>group-a</groupId>
<artifactId>artifact-b</artifactId>
<type>bar</type>
</dependency>
<dependency>
<groupId>groupId-a</groupId>
<artifactId>artifact-a</artifactId>
</dependency>
</dependencies>
</project>
Copy the code
Project B
<project>.<dependencies>
<dependency>
<groupId>group-a</groupId>
<artifactId>artifact-b</artifactId>
<type>bar</type>
</dependency>
<dependency>
<groupId>groupId-a</groupId>
<artifactId>artifact-c</artifactId>
</dependency>
</dependencies>
</project>
Copy the code
In the component dependence and matching is through DependencyManagement {groupId, artifactId, type, classifier}.
GroupId, artifactId, class class, class class, class class, class class, class class, class class, class class, class class, class class, class class, class class, class class, class class, class class, class class, class class, class class So it can also be null if the dependency type is JAR.
Example: Delivering dependent version control
The project a.
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>maven</groupId>
<artifactId>A</artifactId>
<packaging>pom</packaging>
<name>A</name>
<version>1.0</version>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>test</groupId>
<artifactId>a</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>test</groupId>
<artifactId>b</artifactId>
<version>1.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>test</groupId>
<artifactId>c</artifactId>
<version>1.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>test</groupId>
<artifactId>d</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
Copy the code
Project B
<project>
<parent>
<artifactId>A</artifactId>
<groupId>maven</groupId>
<version>1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>maven</groupId>
<artifactId>B</artifactId>
<packaging>pom</packaging>
<name>B</name>
<version>1.0</version>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>test</groupId>
<artifactId>d</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>test</groupId>
<artifactId>a</artifactId>
<version>1.0</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>test</groupId>
<artifactId>c</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
</project>
Copy the code
When Maven runs on project B, version 1.0 of artifactId A, B, C, and D will be used, regardless of the specific version specified in their POM.
- A and C are in project B
dependencies
, so version 1.0 will be used in accordance with the nearest principle. - Because project B’s parent, project A’s
dependencyManagement
If b is a dependency of A or C (or a passing dependency), version 1.0 is also used. Scope iscompile
Because,DependencyManagement has a priority over the proximity principle. - And d is defined in project B
dependencyManagement
If D is a dependency of A or C (or a passing dependency), version 1.0 will be selected.
BOM
BOM is short for Bill Of Materials. It is translated into Bill Of Materials. I didn’t understand it very well at first.
In plain English, a BOM is a special POM file that is used to manage the versions of items in a project and can be customized.
A project’s root POM file is typically defined as a BOM, along with some version numbers that may need to be relied upon in subprojects.
Here is a BOM POM file.
<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.heiz</groupId>
<artifactId>bom</artifactId>
<version>1.0.0</version>
<! -- Packaging -- poM -->
<packaging>pom</packaging>
<! Define the project version number to be used in the submodule.
<properties>
<spring.version>4.3.4. RELEASE</spring.version>
<spring.boot.version>1.4.2. RELEASE</spring.boot.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<! -- Submodule artifactId -->
<modules>
<module>bom-child</module>
</modules>
</project>
Copy the code
The BOM file defines spring.version and Spring.boot. version. Then ${spring.version} can be used to obtain the version defined in the BOM in the PoM file of the dependencyManagement or subproject.
Using an existing BOM file in a project can be done both by inheritance and import.
summary
This installment focuses on some of the management styles and features Maven relies on. DependencyManagement specifies the version of a dependencyManagement dependencyManagement. The version of a dependencyManagement is dependencyManagement. And special POM document BOM.
That’s all for this episode. If it helps, a “like” is my biggest encouragement.