1. Introduction of Maven
1.1. Why use Maven
- Manually managing jar packages and dependencies between jar packages in a project is cumbersome;
- Projects keep getting bigger, which makes maintenance more troublesome.
- There are a lot of repetitive steps in the project construction process;
1.2. What is Maven
Maven, which translates as “expert” or “connoisseur”, is a pure Java open source project developed under Apache. Based on the Project Object Model (POM) concept, Maven uses a central piece of information to manage the construction, reporting, and documentation steps of a project.
Maven is a project management tool for building and dependency management of Java projects.
Maven can also be used to build and manage projects written in C#, Ruby, Scala, and other languages. Maven was a subproject of the Jakarta project and is now a separate Apache project hosted by the Apache Software Foundation. Maven official website and Maven official website Chinese translation
Maven solves the following problems:
- Project JAR package management
- Automated project construction
- Modular project management
Maven solves these problems:
Jar package management: Determine jar package version information by writing coordinate references in POM objects;
Automated build: Define the life cycle through Maven and automate project build through plug-in calls;
Modular project management: manage by defining the parent Maven project and configuring sub-project modules;
1.3 configure Maven
There are many tutorials for configuring Maven on the web. Here is one: Configuring Maven in IDEA and Eclipse
2. Maven core concepts
2.1. Convention directory structure
When we use Maven for automatic compilation, Maven needs to find the Java source file first, and then automatically compile the bytecode file in the correct location. We can let the development tool IDE and framework know the location of our project resource file in two ways:
(1) Specify the file location in the configuration mode
② Through the trilateral tool and framework agreement
Common wisdom in JavaEE development: convention > configuration > code. The basic idea is that problems that can be solved by configuration need not be coded, and problems that can be solved by convention need not be configured. Maven automates the build of our Maven project by contracting the project directory.
The agreed project directory structure is very important for Maven to automate the build. Maven can find the resource files and test files under the agreed project directory structure to automate the build of the project. Creating projects that do not follow the agreed directory structure will result in Maven not being able to recognize the contents of the project and not being able to automate the project build.
The project directory structure as agreed in Maven:
Demo project file directory | - SRC project source files directory | -- - | -- - the main project master file directory | -- - | -- - | - Java project Java file directory | -- - | -- - | - resources project resource file directory | -- - | -- - test test file directory | -- - | -- - | - Java test Java file directory | -- - | -- - | - resources test resource file directory | - target After packaging, the project output directory (the directory will be generated after follow Maven packaging orders) | -- - | -- - classes compiled output directory | -- - | -- - test - test classes compiled output directory | - pom. The XML Maven build filesCopy the code
2.2. The POM
POM: The Project Object Model is the basic unit of work of The Maven Project. It is an XML file, pom.xml, that we define in the Project path. It contains the basic information of the Project, describing how the Project is built, the dependencies required in the Project, and so on.
Maven first looks for the POM in the current project directory when executing a task or goal, reads the configuration in the POM, and builds the project according to the configuration.
Typical POM files:
<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">
<! -- Model version -->
<modelVersion>4.0.0</modelVersion>
<! -- Unique symbol of a company or organization -->
<groupId>cn.bruce</groupId>
<! -- unique ID of the project. There may be more than one project in a groupId.
<artifactId>maven-demo</artifactId>
<! -- Version number of this project -->
<version>1.0 the SNAPSHOT</version>
</project>
Copy the code
Project management can be achieved by configuring POM files. There are many other configurations in POM files, which will be discussed in the following sections.
Full POM file information: Maven POM
2.3 coordinates
Similar to the (X,y,z) coordinates used in mathematics to represent a point in three-dimensional space, Maven uses three vectors (the GAV model) to locate a Maven project in a repository. These three vectors are:
- GropId: indicates the id of an organization
- ArtifactId: indicates the module name
- Version: version
Use the
Example:
<dependencies>
<dependency>
<! -- dependent organization name -->
<groupId>mysql</groupId>
<! -- dependent module name -->
<artifactId>mysql-connector-java</artifactId>
<! -- dependent version -->
<version>8.0.17</version>
</dependency>.</dependencies>
Copy the code
Common words in the version:
- SNAPSHOT: indicates an unstable SNAPSHOT version
- RELEASE/GA: Stable version
The coordinates correspond to the jar packages in the local repository:
Coordinates in POM files:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.3.4. RELEASE</version>
</dependency>.</dependencies>
Copy the code
Paths in the actual warehouse:
Instead of placing jars in the project directory, the Maven project points out reference locations in the repository in the POM. Specific dependent JARS are stored in the local repository.
2.4. Rely on
The dependency management function of Maven is to manage the jar packages used in the project. In other words, dependencies are the jar packages used in the project. Dependency management is the jar package management in the project, but also can manage the scope of use of dependencies, dependencies between the transfer relationship, unified dependency version and other issues. We use the coordinate function mentioned earlier to import jar packages in the project, for example, import MySQL driver in the project.
<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>cn.bruce</groupId>
<artifactId>maven-demo</artifactId>
<version>1.0 the SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.12</version>
</dependency>
</dependencies>
</project>
Copy the code
2.4.1. Scope of Dependency:
Dependency scopes are used to control dependency relationships with the three classpath types (compile classpath, test classpath, and run classpath). Maven has the following dependency scopes.
complie
: Compile dependency scope. If not specified, the dependency scope is used by default. Maven dependencies that use this dependency scope are valid for all three classpath runs for compile tests.test
: Tests the dependency scope. Maven dependencies that use this scope are valid only for the classpath of the test and cannot be relied upon when compiling or running the main code. The classic example is jUnit, which only works when you compile the test code and run it.provided
: Dependency scopes have been provided. Maven dependencies that use this scope are valid for compilation and test classpath, but not at run time. The classic example is servlet-API, which is required for compiling and testing projects, but does not need to be introduced repeatedly by Maven at run time because the container is already provided. You don’t need to pack it when you pack it. Other facilities will provide it. In fact, this dependency can theoretically participate in compilation, test, run, and so on. Equivalent to compile, but exclude is included in the packaging phase.runtime
: Runtime dependency scope. Maven dependencies that use this scope are valid for testing and running classpath, but not when compiling main code. A typical example is the JDBC driver implementation. The compilation of the main code of the project only requires the JDBC interface provided by the JDK, and only requires the JDBC driver to implement the interface when executing or running testssystem
: System dependency scope. In terms of participation, it is the same as provided, except that dependencies are not downloaded from the Maven repository, but from the local file system. The systemPath attribute needs to be added to define the path. This dependency is exactly the same as the classpath and Provided dependency scopes of the three scopes. May cause non-portability. Use with caution.import
: Imports the dependency scope. This dependency scope has no real impact on the three Classpath types. Effect only under dependencyManagement.
Common declaration cycle range comparison:
complie | test | provided | |
---|---|---|---|
Whether it is valid for the main program | is | no | is |
Whether to participate in the testing phase | is | is | is |
Deployment Or Not | is | no | no |
Use the
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.12</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
<! -- Effective in test phase -->
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<! Exclude this dependency at deployment time -->
<scope>provided</scope>
</dependency>
</dependencies>
Copy the code
2.4.2. Dependency passing
Dependencies are transitive. We import jars that depend on other JARS, and Maven passes the jars that the jars depend on at the same time.
Such as: The spring-boot-stater:2.1.8.RELEASE jar is used in the project, but this jar also depends on other jars. Maven will also pass the jar package that depends on spring-boot-stater:2.1.8.RELEASE to the project, as shown in the following figure:
Benefits: Transitive dependencies do not have to be written in every project; they are configured in the public project and other project dependencies can be used.
Maven – for example: we are the dependence is configured in the demo project, introduced in the maven project – model – 1 maven – demo depend on, can be used in maven project – model – 1 maven – demo relies upon the jar package.
maven-demo
The POM structure of the project
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.12</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.1.8. RELEASE</version>
</dependency>
</dependencies>
Copy the code
maven-model-1
POM structure of the project:
<dependencies>
<dependency>
<groupId>cn.bruce</groupId>
<artifactId>maven-demo</artifactId>
<version>1.0 the SNAPSHOT</version>
</dependency>
</dependencies>
Copy the code
Using the Maven management tool of IDEA, you can view that the maven-Model-1 project has imported the dependencies required by maven-Demo project.
We notice that there are some dependencies in Maven-demo that are not passed to Maven-Model-1 because non-compile scope dependencies cannot be passed.
2.4.3. Exclusion of dependencies
In this case, Maven will introduce both A and B into the current project. However, we have already introduced B in the project, so we want A to directly depend on B in the project instead of the original B. Therefore, we need to exclude the dependency of B in A.
The main purpose of dependency exclusion is also to uniformly manage the dependent versions in the project by using the < Exclusion >
TAB in the POM file.
Sample code:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</exclusion>
</exclusions>
</dependency>
Copy the code
Before exclusion:
After the rule out:
2.4.4. Principle of dependency
We can use dependency exclusion to solve the problem of dependency conflict in the project, and Maven also provides a solution to solve the dependency conflict, that is, if we do not solve the problem, Maven will help us to solve it, but it is not recommended. It is best to solve the dependency conflict to avoid the instability of the project.
Maven’s principles for conflict resolution:
① Shortest path priority
As shown in the figure, project A depends on project B, and project B depends on project C, and project A, project B, and project C depend on slf4J-API at different versions. The dependency paths of project A, B, and C on SLF4J-API are 1, 2, and 3 respectively. According to the shortest path principle, the final version of SLF4J-API introduced in Project A was 1.7.30
Path: Module level between the current project and dependent Maven projects.
② The first to declare is preferred
POM files in project A:
<dependencies>
<dependency>
<groupId>cn.bruce</groupId>
<artifactId>projectB</artifactId>
<version>1.0.1. The SNAPSHOT</version>
</dependency>
<dependency>
<groupId>cn.bruce</groupId>
<artifactId>projectC</artifactId>
<version>1.0.1. The SNAPSHOT</version>
</dependency>
</dependencies>
Copy the code
As shown in the figure, PROJECT A depends on both project B and project C, and project A, project B, and project C depend on slF4J-API at different versions. In this case, the version of slF4J-API in project A depends on the location of project B and project C dependencies declared in project A. In project A’s POM file, projectB’s declaration precedes projectC’s declaration, so the project uses the SLF4J-API specified in projectB :1.7.23
Declaring first refers to the order in which
tags are declared
2.4.5. Unified management of dependent versions
We may rely on a set of jars for the same framework in a project, and it is best to use the same version of the jar when we use it. If we use the above content, we need to change the version of each dependency in the framework and set it up one by one. Maven provides us with the same version
POM files in the project
<properties>
<spring.version>5.0.0</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-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
</dependencies>
Copy the code
At this point, all versions of Spring jar packages in the project depend on 5.0.0. If you want to upgrade to 5.0.1, you only need to change the version number in the < Properties > TAB. Therefore, it is recommended that the project rely on jar packages to use the
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
Copy the code
2.4.6. Find Maven project version
When we specify dependency information in the POM file (that is, after locating the specified JAR package version), Maven’s lookup order is as follows:
Maven will first look for jars in our local repository.
② If you cannot find it in the local repository, go to Maven private server to find it.
③ If the jar package is not found in Maven private server, it will be searched in remote repository and downloaded to local.
⑤ Next time in the use of direct reference to the local repository jar package;
Search process: local -> private -> remote repository
2.5. The warehouse
2.5.1. Classification of warehouse
① Local repository: the repository in this machine serves all Maven projects on the local machine
② Remote warehouse
- Maven private server: Deployed on a LOCAL area network (LAN) to serve Maven projects within the current LAN.
- Maven central Repository: Deployed on the Internet to serve Maven projects worldwide;
- Maven central repository mirroring: Takes the pressure off the central repository and provides faster dependency request services, such as Ali Cloud Mirror repository
2.5.2. Files in the warehouse
What’s in the repository: Maven project
- Plugins for Maven itself
- Third-party framework or tool JAR packages
- Maven project that we developed ourselves
2.6. Lifecycle/plug-in/target
2.6.1. Life cycle
Maven’s life cycle refers to the steps Maven takes to execute a build project. Maven’s life cycle defines the execution sequence of each step. With the execution sequence list, Maven can automate the execution of build commands.
Maven has three life cycles:
① Clean Lifecycle will be performed before the actual project is built.
② The core part of the Default Lifecyle build, compile, test, package, install, deploy, etc.
③ Site Lifecycle will generate project reports, sites and release sites.
2.6.1.1 Clean Life Cycle
phase | describe |
---|---|
pre-clean |
Perform required processes prior to actual project cleanup |
clean |
Delete all files generated in the previous version |
post-clean |
Perform the procedures required to complete the project cleanup |
6.1.2 Default Life Cycle
The Default life cycle is the most important one in Maven’s life cycle, where most of the work takes place.
phase | describe |
---|---|
validate |
Verify that the project is correct and provide all necessary information. |
initialize |
Initialize the build state, such as setting properties or creating directories. |
generate-sources |
Generate any source code to be included in the build. |
process-sources |
Process source code, such as filtering any values. |
generate-resources |
Generate resources for inclusion in packages. |
process-resources |
Copy and process resources into the target directory for packaging. |
compile |
Compile the source code for the project. |
process-classes |
Post-processing of compiled files, such as bytecode enhancement of Java classes. |
generate-test-sources |
Generate any test source code for inclusion in the build. |
process-test-sources |
Process test source code, such as filtering all values. |
generate-test-resources |
Create test resources. |
process-test-resources |
Copy and process the resource into the test target directory. |
test-compile |
Compile the test source code into the test target directory |
process-test-classes |
Post-processing of generated files from test compilations, such as bytecode enhancement of Java classes. |
test |
Run tests using an appropriate unit testing framework. These tests should not require code to be packaged or deployed. |
prepare-package |
Perform any actions necessary to prepare the packaging prior to the actual packaging. This usually results in packaging of the unpackaged, processed version. |
package |
Take the compiled code and package it into a distributable format, such as a JAR. |
pre-integration-test |
Perform the required actions before performing integration tests. This might involve things like setting up the required environment. |
integration-test |
Process the package and deploy it to an environment where you can run integration tests, if necessary. |
post-integration-test |
Perform the required actions after the integration test is executed. This may include cleaning up the environment. |
verify |
Conduct any inspection to confirm that the package is valid and complies with quality standards. |
install |
Install software packages into a local repository as dependencies in other local projects. |
deploy |
When completed in an integration or publishing environment, the final package is copied to a remote repository for sharing with other developers and projects. |
6.1.3 Site Life Cycle
It is used to create reports, deploy sites, and so on.
phase | describe |
---|---|
pre-site |
Perform the required procedures before the actual project site is generated |
site |
Generate site documentation for the project |
post-site |
Perform the procedures required to complete site generation and prepare for site deployment |
site-deploy |
Deploy the generated site document to the specified Web server |
Maven build lifecycle features:
- Order of execution of each build link: Do not disrupt the order, must be executed in the correct order;
- The Maven core program defines an abstract life cycle in which specific tasks are performed by plug-ins.
- Maven executes sequentially, starting at the beginning of any phase of the execution life cycle;
2.6.2. Plug-ins and plug-in goals
Maven’s core program defines only abstract life cycles. Specific work needs to be done through specific plug-ins. Plug-ins themselves are not included in maven’s core program. When a project is built, Maven will first look for plug-ins in the local repository and, failing to find them, download them in the remote repository.
Each plug-in can implement multiple functions, and each function is a plug-in goal;
The Maven lifecycle is tied to the goals of the plug-in to accomplish a specific build task;
Plug-in objectives:
- The phases of the life cycle only define what tasks to perform
- Each phase corresponds to the goals of the plug-in
- Similar goals are accomplished by plug-ins
- You can think of a target as a command that invokes a function
Life cycle stage | Plug-in goals | The plug-in |
---|---|---|
compile | compile | maven-compiler-plugin |
test-compile | test-compile | maven-compiler-plugin |
. | . | . |
2.7. Inheritance
We want to have uniform management of junit dependencies in the project. Since dependencies in the Test scope cannot be passed, it is easy to cause version inconsistencies. Maven gives us an inherited way to solve these problems.
Solution: Specify the complete dependency information of junit in the parent project. The version is not specified when declaring junit dependencies in the child project
Operation steps:
① Create a parent Maven project and package it in POM mode
② Declare the application of the parent project in the child project
③ Manage the dependent versions in the parent project
④ Use the version managed in the parent project in the child project without writing the version information
Code examples:
① Create a parent Maven project and package it in POM mode
<groupId>cn.bruce</groupId>
<artifactId>maven-demo</artifactId>
<version>1.0 the SNAPSHOT</version>
<name>maven-demo</name>
<packaging>pom</packaging>
Copy the code
② Declare the application of the parent project in the child project
Use the
<parent>
<artifactId>maven-demo</artifactId>
<groupId>cn.bruce</groupId>
<version>1.0 the SNAPSHOT</version>
<relativePath>../maven-demo/pom.xml</relativePath>
</parent>
Copy the code
③ Manage the dependent versions in the parent project
Use the
<dependencyManagement>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>
Copy the code
④ Use the version managed in the parent project in the child project without writing the version information
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
Copy the code
2.8. The aggregation
Projects get bigger as the business grows, and more modules are involved, and it would take a lot of time and effort to execute a declaration cycle for each module. Maven provides aggregation for unified module management.
The purpose of aggregation: To manage the participating modules in a “total aggregation project.
In the aggregation module, use the tag:
Specific operation:
1. Configure the aggregation module
Configure the modules you want to aggregate using the
<modules>
<module>../maven-model-1</module>
<module>../maven-model-2</module>
</modules>
Copy the code
After configuring submodules in the aggregation module, you can use the Maven tool in IDEA to view that the aggregation module has the identity of [root]
You can see the results of Maven’s execution after the aggregation module executes its life cycle
. [INFO] maven-parent ....................................... SUCCESS [s] 1.361 [INFO] maven - model - 1... SUCCESS [s] 0.003 [INFO] maven - model - 2... SUCCESS [s] 0.002 [INFO] -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 1.710s [INFO] Finished at: 2020-12-14T15:22:16+08:00 [INFO] ------------------------------------------------------------------------Copy the code
Inheritance, aggregation, and dependency delivery are often used together in actual project construction for unified management of project dependencies and lifecycle.
- Unified dependency management: Configure the version information of common dependencies in each submodule in the parent Maven project. The submodule inherits the parent module to facilitate unified dependency management.
- Unified life cycle management: After a child module is configured in the parent module, unified life cycle operations can be performed on the parent module.