maven coordinates a specific explanation:MAVEN defines a set of rules: Any component in the world can be uniquely identified using MAVEN coordinates. The elements of the MAVEN coordinates include GROUPID, Artifactid, version, packaging, classifier. We just need to provide the correct coordinate elements, and Maven can find the corresponding artifacts. For example, when you need to use the 5.8 version number of testng on the Java5 platform, tell maven: "GROUPID=ORG.TESTNG; artifactid=testng; version=5.8; Classifer=jdk15,maven will look for the corresponding widget from the Central warehouse (http://search.maven.org/#browse) for our use. Look at a set of coordinate definitions first. For example, the following:
<groupId>org.sonatype.nexus</groupId> <artifactId>nexus-indexer</artifactId> <version>2.0.0</version> <packaging>jar</packaging>
Nexus-indexer is a class library that compiles and provides search functionality to the MAVEN repository, which is a submodule in the Nexus Project. The nexus will be described in detail later.
The following is a detailed explanation of the individual coordinate elements: groupId: defines the actual project that the current MAVEN project belongs to. First, the MAVEN project and the actual project do not necessarily have a one-off relationship. This is a practical project, for example Springframework. The corresponding MAVEN projects will be very many, such as Spring-core, Spring-context and so on. An actual project is generally divided into multiple project modules.
GroupID should not only be relevant to the organization or company under which the project belongs, because there will be a lot of actual projects under one organization, assuming that GroupID is only defined at the organization level and can be seen later. Artifactid only can be the corresponding MAVEN project. Then the actual project layer will be difficult to define.
Finally, the GroupID is represented in a similar way to the Java package name, usually corresponding to the reverse one by one of the domain name.
Artifactid: This element defines a MAVEN project (module) in the actual project. The recommended practice is to use the actual project name as the prefix for the Artifactid.
For example, the Artifactid is nexus-indexer, using the actual project name Nexus as the prefix. The advantage of this is that it is convenient to find the actual component. Version : This element defines the version number where the MAVEN project is currently located.
In fact, MAVEN defines a complete set of version number specifications, as well as the concept of snapshots (SNAPSHOT). The following chapters will be discussed in detail. Packaging: This element defines how the MAVEN project is packaged. First, the packaging method is usually the same as the file extension of the generated artifact, as in the example above, packaging is the jar and finally the file name is Nexus-indexer-2.0.0.jar. It's a MAVEN project with a war package. Finally, the generated artifacts will have a. war file. But that's not absolute.
When packaging is not defined, MAVEN will use the default value jar.
classifier: This element is used to help define some of the subordinate artifacts of the component output.
The subordinate member is corresponding to the main component. As in the previous example, the main component is Nexus-indexer-2.0.0.jar. The project also generates some ancillary artifacts, such as Nexus-indexer-2.0.0-javadoc.jar and Nexus-indexer-2.0.0-sources.jar, through plugins that include Java documentation and source code. At this time, Javadoc and sources are the classifier of these two subordinate components. Such A subordinate member has its own unique coordinate. Note: The classifier of the project cannot be defined directly, because the subordinate artifacts are not generated directly by default, but are generated by the additional plug-in Help. The file name of the project artifact is corresponding to the coordinates, and the general rule is artifactid-version[-classifier].packaging,[-classifier] indicates optional. It is also important to emphasize that packaging is not necessarily corresponding to the component extension, for example, packaging is a maven-plugin component with a jar extension.
Dependent configuration: A dependency declaration can include elements such as the following:
<project> ... <dependencies> <dependency> <groupId>...</groupId> <artifactid>, .... </artifactId> <version>...</version> <type>...</type> <scope> ...</scope> <optional>...</optional> <exclusions> <exclusion> ... </exclusion> ... </exlusions> </dependency> ... </dependencies> ...</project>
The dependencies under the root element project can include one or more denpendency elements to declare one or more project dependencies.
The elements that each dependency can include are:
- GroupId, Artifactid, and version: the basic coordinates of the dependency, for whatever a dependency, the basic coordinates are the most important, MAVEN can find the required dependency based on the coordinate ability.
- Type: The dependent types, corresponding to the packaging defined by the project coordinates. Most of the cases. The element does not have to be declared, and its default value is jar.
- Scope: The range of dependencies. Please see the following section
- Optional: Whether the tag dependency is optional, see the following section
- Exclusions: To exclude transitive dependencies, see the following subsections
maven Dependency Range:In Maven, the dependency range is used in elementsScopeSaid. Maven runs the compile, test, and run three sets of different classpath.
The scope of dependency is to control the relationship of dependencies with these three classpath (compile classpath, test classpath, execute classpath). MAVEN has the following range of dependencies: compile: compilation dependency Range.
Assuming it is not specified, the dependency scope is used by default. This dependency range is valid for compiling, testing, and executing three kinds of classpath. The typical example is Spring-core, which is used when compiling, testing, and executing. test: test-dependent range.
This dependency is only valid for Test classpath. This type of dependency cannot be used when compiling the master code or executing the project. A typical example is JUnit. It only needs to compile the test code and perform the test environment.
provided: The range of dependencies has been provided. This dependency range is valid for test and execution Class-path, but is not valid at execution time. The typical example is SERVLET-API. This dependency is required for compiling and testing projects. But when it comes to executing the project. Because the container is already available, there is no need for MAVEN to introduce it again and again. Runtime: The execution time dependent range.
This range is dependent, valid for execution and test Class-path, but not valid when compiling the master code. A typical example is the JDBC driver implementation. The compilation of the project master code requires only the JDBC interface provided by the JDK, and it is only necessary to implement the detailed JDBC driver for the above interface when performing a test or execution of the project.
System : The range of systems dependencies. The dependence is in line with the three kinds of classpath, and the provided-dependent range is completely consistent. However, you must explicitly specify the path to the dependent file through the Systempath element when using system-wide dependencies. Because such dependencies are not parsed by the MAVEN repository and are often bound to native systems, this can cause the build to be non-portable and therefore should be used with caution.
The Systempath element can reference environment variables. Such as:
<dependency> <groupId>javax.sql</groupId> <artifactid>jdbc-stdext</ artifactid> <version>2.0</version> <scope>system</scope> <systempath >${java.home}/lib/rt.jar</systemPath></dependency>
Import:Import the dependency range. The dependency scope does not have a real impact on three classpath, and we will cover that dependency in a later section.
transitive dependencies: What is transitive dependency: transitive dependency means that project a relies on the B component. In the pom.xml of the B-component, the C component is also explicitly dependent. Then a project will be dependent on the C component. In projects that do not use MAVEN, we often need to manually look for all the components that are used directly and indirectly (transitive dependencies). And resolve the issue of version number conflicts, which will be very expensive and significant. Maven's transitive dependency mechanism is a great solution to this problem. There is a org.springframework:spring-core:2.5.6 dependency under a project, and in fact Spring-core has its own dependence, For example spring-core-2.5.6.pom the file includes a commos-logging dependency, see the following code:
<dependency> <groupId>commons-logging</groupId> <artifactid>commons-logging </artifact> <version>1.1.1</version> </denpendency>
Commons-logging does not declare a dependency scope, its dependency is the default compile. And the spring-core of the general range of dependence is also compile. A project has a compile range of spring-core dependencies. Spring-core has a compile range of commons-logging dependencies. Then commons-logging will become the compile range dependency of the A project. Commons-logging is a transitive dependency of account-email. With a transitive dependency mechanism, you don't have to think about what it depends on when you use the spring framework, or worry about introducing more dependencies.
Maven parses each of the directly dependent Pom. The necessary indirect dependencies are introduced into the current project in the form of transitive dependencies.
transitive dependencies and dependencies: If a relies on b,b with C, we say that A is the first direct dependence on B, and B is the second direct dependence on C. A for C is transitive dependency. The scope of the first direct dependence and the scope of the second direct dependence determine the scope of the transitive dependency.
For example, as seen in the following table, the leftmost column represents the first direct dependency range. The top row represents the second direct dependency range. The middle intersection cell represents the transitive dependency range.
|
compile |
test |
provided |
runtime |
compile |
compile |
- |
- |
runti Me |
test |
test |
- | TD valign= "Top" > -
test |
provided |
provided |
- |
&NBSP ; - |
provided |
runtime |
runtime |
- |
- |
runtime |
Careful observation of the table, can be found such as the following rules: When the second direct dependence of the range is compile. The scope of transitive dependency is consistent with the scope of the first direct dependency. When the second direct dependence is in the range of test, the dependency will not be passed, and when the second direct dependence is provided, only the first direct dependency range is provided dependent, and the transitive dependency is the same as provided When the second direct dependence is the runtime. The scope of transitive dependency is consistent with the scope of the first direct dependency, but compile exceptions. At this point, the scope of transitivity dependency is runtime.
Dependent Mediation:Maven's transitive dependency mechanism, on the one hand, greatly simplifies and facilitates dependency declarations.
But sometimes when problems are caused. We need to know which dependency path the transitive dependency was introduced from. For example, project A has this dependency: a->b->c->x (1.0), A->d->x (2.0), X is the transitive dependency of a, but two X on the two dependent path, which x is used by MAVEN parsing? It is not possible to resolve two version numbers, because they can cause repeated dependencies. The first principle of Maven dependency is that the path is the most recent priority. In this example, X (1.0) has a path length of 3, and X (2.0) has a path length of 2. So x (2.0) will be parsed for use. Maven defines a second principle that relies on mediation: the first one is preferred. Depending on the length of the dependent path, the order in which the claims are dependent in the Pom determines who will be parsed. The first of the order depends on the winner.
Optional dependencies: If you have dependencies for the following states: A->b, b->x (optional), b->y (optional). Based on the definition of transitive dependency, if all of the three dependent scopes are compile, then X, y is the compile range transitive dependency of a.
However. Because X and y are optional dependencies here, dependency will not be passed. The reason for using optional dependencies may be that B implements two features, one of which is dependent on X. Attribute two relies on Y, and the two attributes are mutually exclusive, and the user cannot use both features at the same time. For example, B is a persistent Layer isolation toolkit that supports a variety of databases, including Mysql,postgresql, when building toolkits. Drivers for both of these databases are required. But when it comes to using the toolkit. Rely on only one database. The dependency declarations for item B are shown below for example:
<project > <modelVersion>4.0.0</modelVersion> <groupId>com.juvenxu.mvnbook</groupId> <art ifactid>project-b</artifactid> <version>1.0.0</version> <dependencies> <DEP Endency> <groupId>mysql</groupId> <artifactid>mysql-connector-java</ar Tifactid> <version>5.1.10</version> <optional>true</optional> </dependency> <dependency> <groupId>postgresql</groupId> <artifactId>postgresql</artifactId> <version>8.4-701.jdbc3</version> & lt;optional>true</optional> </dependency> </dependencies></project>
In the Pom.xml. Use
<optional>The elements represent Mysql-connector-java and PostgreSQL dependencies as optional dependencies, which only affect the current project B and are not passed when other projects depend on B. Therefore, when project a relies on project B, it is assumed that the de facto use is based on the MySQL database. Then in a project want to display the Mysql-connector-java this dependency, see the following a project Pom.xml.
<project> <modelVersion>4.0.0</modelVersion> <groupid>com.juvenxu.mvnbook</ groupid> <artifactId>project-a</artifactId> <version>1.0.0</version> <dependencies> <dependency> <groupId>com.juvenxu.mvnbook</groupId> < artifactid>project-b</artifactid> <version>1.0.0</version> </dependency> <dependency> <groupId>postgresql</groupId> <artifactid>postgresql</ artifactid> <version>8.4-701.jdbc3</version> </dependency> </ Dependencies></project>
In an ideal situation, an optional dependency should not be used. Using an optional dependent background is a project that implements multiple features, and in object-oriented design, there is a single principle of responsibility, meaning that a class should have only one responsibility, not too many functions.
In the example above, a better approach would be to create a MAVEN project for MySQL and PostgreSQL, respectively. Assign different Artifactid based on the same groupid, such as Com.juvenxu.mvnbook;project-b-mysql and Com.juvenxu.mvnbook:project-b-postgresql, The corresponding JDBC driver dependency is declared in the respective Pom, and the optional dependency is not applicable, and the user chooses to use Project-b-mysql or project-b-postgresql as required. Because of the role of transitive dependencies. The JDBC driver dependency is no longer declared.
Best Practices: exclude dependencies: transitive dependencies, while simplifying the management of project dependencies, sometimes create problems that require us to exclude some transitive dependencies. For example: The current project has a third-party dependency, and this third-party dependency relies on the snapshot version number of a class library. Then this snapshot will become a transitive dependency of the current project. And snapshot's instability will directly affect the current project. This is the time to rule out the snapshot and declare an official version number of the library in the current project.
In other cases, you may also need to exclude reliance, for example Sun JTA Api,hibernate relies on this jar. However, because of the version number factor, the class library is not in the central repository. There is a corresponding implementation in the Apache Geronimo project. You will then be able to exclude the sun JAT API. Then declare the JTA API implementation of Geronimo. Exclude dependent sample code such as the following:
<project> <modelVersion>4.0.0</modelVersion> <groupid>com.juvenxu.mvnbook</groupid > <artifactId>project-a</artifactId> <version>1.0.0</version> <dependencies> <dependency> <groupId>com.juvenxu.mvnbook</groupId> <artifactid> ;p roject-b</artifactid> <version>1.0.0</version> <exclusions> <exclusion> <groupId>com.juvenxu.mvnbook</groupId> <artifactId>project-c</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>com.juvenxu.mvnbook</groupId> <artifactId>project-c</artifactId> <version>1.1.0</version> </DEP Endency> </dependenCies></project>
The code uses the exclusions element declaration to exclude dependencies, exclusions can include one or more exclusion child elements, so one or more transitive dependencies can be excluded.
collation Dependent: very many times. We use different modules from the same project, and the dependent version numbers are the same. For example, when we use the spring framework, the dependencies we introduce separately are org.springframework:spring-core:2.5.6, org.springframework:spring-beans:2.5.6, org.springframework:spring-context:2.5.6, org.springframework:spring-support:2.5.6. Assuming you need to upgrade spring frame-work in the future, these dependent version numbers will be upgraded together. The ability to use collation dependencies in Maven avoids repetition and reduces the chance of errors when changing values. Examples include the following:
<project> <modelVersion>4.0.0</modelVersion> <groupid>com.juvenxu.mvnbook</groupid > <artifactId>account-email</artifactId> <name>account email</name> <version> 1.0.0-snapshot</version> <properties> <springframework.version>2.5.6</springframewo rk.version> </properties> <dependencies> <dependency> <groupid>o Rg.springframework</groupid> <artifactId>spring-core</artifactId> <versio N>${springframework.version}</version> </dependency> <dependency> < Groupid>org.springframework</groupid> <artifactId>spring-beans</artifactId> <version>${springframework.version}</version> </dependency> <dependency> <groupid>org.sprIngframework</groupid> <artifactId>spring-context</artifactId> <version> ${springframework.version}</version> </dependency> <dependency> <group Id>org.springframework</groupid> <artifactId>spring-support</artifactId> &L T;version>${springframework.version}</version> </dependency> </dependencies></project >
The Maven attribute is used here (the MAVEN properties are described in detail later). When Maven executes, it replaces all ${springframework.version} in the Pom with the actual value 2.5.6.
Other words. The Maven attribute can be referenced in the same way that the dollar sign and the braces surround it. The Sping framework dependent version number value is then represented by this property reference.
Optimize dependencies: MAVEN will proactively parse the direct and transitive dependencies of all projects, and correctly infer the scope of each dependency according to the rules. Adjustment is also possible for some dependent conflicts. To make sure that no one component has only a unique version number that exists in the dependency. After these jobs. Finally, those dependencies are called resolved dependencies. Ability to perform commands such as the following to view the resolved dependencies of the current project: mvn dependency:list on this basis. You can also learn more about the information that has been resolved. The dependencies directly in the current project POM declaration are defined as top-level dependencies, and these top-level dependencies are defined as second-level dependencies, ... When these dependencies are parsed by Maven, they form a dependency tree. With this tree of dependency you can see very clearly which path a dependency is introduced into. Ability to perform mvn dependency:tree to view the dependency tree of the current project.
We can also use mvn dependency:analyze to analyze dependencies in a project.
There are two types of content that can be derived from this tool:used undeclared dependencies means used in the project. However, there is no explicit declaration of dependency. This reliance is intended to be a potential risk. The current project is using them directly. For example, there are a lot of related Java import declarations, and such dependencies are passed in through direct dependencies. When the upgrade is directly dependent, the version number of the relevant transitive dependency may change and the interface may change. This causes the related code in the current project to fail to compile.
So. In general, you should explicitly declare dependencies that are directly used in whatever project.
Unused declared dependencies refers to a dependency that is not used in a project, but explicitly declared. For this type of dependency, we should carefully analyze it, because MVN dependency:analyze only analyzes the dependencies that are needed to compile the main code and test code. Some of the dependencies required to perform the test box execution are not found. Therefore, we should carefully analyze whether the dependence will be used to determine the choice of the dependency.
Copyright notice: This article blog original article. Blogs, without consent, may not be reproduced.
Maven Learning Notes (iv): Coordination and dependency