3. A Simple Maven Project

3.1. Introduction

In this chapter, we introduce a simple project created from scratch using the Maven Archetype plugin. This elementary application provides us with the opportunity to discuss some core Maven concepts while you follow along with the development of the project.

Before you can start using Maven for complex, multi-module builds, we have to start with the basics. If you’ve used Maven before, you’ll notice that it does a good job of taking care of the details. Your builds tend to “just work,” and you only really need to dive into the details of Maven when you want to customize the default behavior or write a custom plugin. However, when you do need to dive into the details, a thorough understanding of the core concepts is essential. This chapter aims to introduce you to the simplest possible Maven project and then presents some of the core concepts that make Maven a solid build platform. After reading it, you’ll have a fundamental understanding of the build lifecycle, Maven repositories, dependency management, and the Project Object Model (POM).

3.1.1. Downloading this Chapter’s Example

This chapter develops a very simple example which will be used to explore core concepts of Maven. If you follow the steps described in this chapter, you shouldn’t need to download the examples to recreate the code produced by the Maven. We will be using the Maven Archetype plugin to create this simple project and this chapter doesn’t modify the project in any way. If you would prefer to read this chapter with the final example source code, this chapter’s example project may be downloaded with the book’s example code at:

http://books.sonatype.com/mvnex-book/mvnex-examples.zip

Unzip this archive in any directory, and then go to the ch-simple/ directory. There you will see a directory named simple that contains the source code for this chapter.

3.2. Creating a Simple Project

To start a new Maven project, use the Maven Archetype plugin from the command line. Run the archetype:generate goal, select default archetype suggested by pressing “Enter”. This will use the archetype org.apache.maven.archetypes:maven-archetype-quickstart. Press “Enter” again to confirm the latest version of the archetype and then “Enter” to confirm the supplied parameters.

Warning

At the time of publication, the default maven-archetype-quickstart was item #312 in a list of 860 available archetypes. As more and more projects release Maven archetypes, this list will change and the number for the default archetype may change. When you run archetype:generate as shown below, the default maven-archetype-quickstart will be selected by default.

$ mvn archetype:generate -DgroupId=org.sonatype.mavenbook -DartifactId=simple -Dpackage=org.sonatype.mavenbook -Dversion=1.0-SNAPSHOT
[INFO]
[INFO] -----------------------------------------------------
[INFO] Building Maven Stub Project (No POM) 1
[INFO] -----------------------------------------------------
[INFO]
[INFO] >>> maven-archetype-plugin:2.2:generate (default-cli) @ standalone-pom >>>
[INFO]
[INFO] <<< maven-archetype-plugin:2.2:generate (default-cli) @ standalone-pom <<<
[INFO]
[INFO] --- maven-archetype-plugin:2.2:generate (default-cli) @ standalone-pom ---
[INFO] Generating project in Interactive mode
[INFO] No archetype defined. Using maven-archetype-quickstart (org.apache.maven.archetypes:maven-archetype-quickstart:1.0)
Choose archetype:
...
312: remote -> org.apache.maven.archetypes:maven-archetype-quickstart (An archetype which contains a sample Maven project.)
Choose a number or apply filter (format: [groupId:]artifactId, case sensitive contains): 312:
Choose org.apache.maven.archetypes:maven-archetype-quickstart version:
1: 1.0-alpha-1
2: 1.0-alpha-2
3: 1.0-alpha-3
4: 1.0-alpha-4
5: 1.0
6: 1.1
Choose a number: 6:
[INFO] Using property: groupId = org.sonatype.mavenbook
[INFO] Using property: artifactId = simple
[INFO] Using property: version = 1.0-SNAPSHOT
[INFO] Using property: package = org.sonatype.mavenbook
Confirm properties configuration:
groupId: org.sonatype.mavenbook
artifactId: simple
version: 1.0-SNAPSHOT
package: org.sonatype.mavenbook
 Y: :
[INFO] ---------------------------------------------------------
[INFO] Using following parameters for creating project from Old (1.x) Archetype: maven-archetype-quickstart:1.1
[INFO] ---------------------------------------------------------
[INFO] Parameter: groupId, Value: org.sonatype.mavenbook
[INFO] Parameter: packageName, Value: org.sonatype.mavenbook
[INFO] Parameter: package, Value: org.sonatype.mavenbook
[INFO] Parameter: artifactId, Value: simple
[INFO] Parameter: basedir, Value: /Volumes/mac-data/dev/github/sonatype
[INFO] Parameter: version, Value: 1.0-SNAPSHOT
[INFO] project created from Old (1.x) Archetype in dir: /Volumes/mac-data/dev/github/sonatype/simple
[INFO] BUILD SUCCESS
...

mvn is the Maven command. archetype:generate is called a Maven goal. An archetype is defined as “an original model or type after which other similar things are patterned; a prototype.” A number of archetypes are available in Maven for anything from a simple application to a complex web application, and the archetype:generate offers a list of archetypes to choose from. In this chapter, we are going to use the most basic archetype to create a simple skeleton starter project. The plugin is the prefix archetype, and the goal is generate.

Once we’ve generated a project, take a look at the directory structure Maven created under the simple directory:

simple/(1)
simple/pom.xml(2)
/src/
/src/main/(3)
/main/java
/src/test/(4)
/test/java

This generated directory adheres to the Maven Standard Directory Layout. We’ll get into more details later in this chapter, but for now, let’s just try to understand these few basic directories:

(1)The Maven Archetype plugin creates a directory simple that matches the artifactId. This is known as the project’s base directory.
(2)Every Maven project has what is known as a Project Object Model (POM) in a file named pom.xml. This file describes the project, configures plugins, and declares dependencies.
(3)Our project’s source code and resources are placed under src/main. In the case of our simple Java project this will consist of a few Java classes and some properties file. In another project, this could be the document root of a web application or configuration files for an application server. In a Java project, Java classes are placed in src/main/java and classpath resources are placed in src/main/resources.
(4)Our project’s test cases are located in src/test. Under this directory, Java classes such as JUnit or TestNG tests are placed in src/test/java, and classpath resources for tests are located in src/test/resources.

The Maven Archetype plugin generated a single class org.sonatype.mavenbook.App, which is a 13-line Java class with a static main function that prints out a message:

package org.sonatype.mavenbook;

/**
 * Hello world!
 *
 */
public class App
{
    public static void main( String[] args )
    {
        System.out.println( "Hello World!" );
    }
}

The simplest Maven archetype generates the simplest possible program: a program which prints “Hello World!” to standard output.

3.3. Building a Simple Project

The created directory simple contains the pom.xml and you can easily build the project:

$ cd simple
$ mvn install
[INFO] Scanning for projects...
[INFO] -----------------------------------------
[INFO] Building simple
[INFO]task-segment: [install]
[INFO] -----------------------------------------
[INFO] [resources:resources]
[INFO] Using default encoding to copy filtered resources.
[INFO] [compiler:compile]
[INFO] Compiling 1 source file to /simple/target/classes
[INFO] [resources:testResources]
[INFO] Using default encoding to copy filtered resources.
[INFO] [compiler:testCompile]
[INFO] Compiling 1 source file to /simple/target/test-classes
[INFO] [surefire:test]
[INFO] Surefire report directory: /simple/target/surefire-reports

T E S T S

Running org.sonatype.mavenbook.AppTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.105 sec

Results :

Tests run: 1, Failures: 0, Errors: 0, Skipped: 0

[INFO] [jar:jar]
[INFO] Building jar: /simple/target/simple-1.0-SNAPSHOT.jar
[INFO] [install:install]
[INFO] Installing /simple/target/simple-1.0-SNAPSHOT.jar to \
~/.m2/repository/com/sonatype/maven/simple/simple/1.0-SNAPSHOT/ \
simple-1.0-SNAPSHOT.jar

You’ve just created, compiled, tested, packaged, and installed the simplest possible Maven project. To prove to yourself that this program works, run it from the command line.

$ java -cp target/simple-1.0-SNAPSHOT.jar org.sonatype.mavenbook.App
Hello World!

3.4. Simple Project Object Model

Simple Project’s pom.xml 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/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.sonatype.mavenbook.simple</groupId>
    <artifactId>simple</artifactId>
    <packaging>jar</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>simple</name>
    <url>http://maven.apache.org</url>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

This pom.xml file is the most basic POM you will ever deal with for a Maven project, usually a POM file is considerably more complex: defining multiple dependencies and customizing plugin behavior. The first few elements—groupId, artifactId, packaging, version—are what is known as the Maven coordinates which uniquely identify a project. name and url are descriptive elements of the POM providing a human readable name and associating the project with a web site. The dependencies element defines a single, test-scoped dependency on a unit testing framework called JUnit. These topics will be further introduced in Section 3.5, “Core Concepts”, all you need to know, at this point, is that the pom.xml is the file that makes Maven go.

Maven always executes against an effective POM, a combination of settings from this project’s pom.xml, all parent POMs, a super-POM defined within Maven, user-defined settings, and active profiles. All projects ultimately extend the super-POM, which defines a set of sensible default configuration settings. While your project might have a relatively minimal pom.xml, the contents of your project’s POM are interpolated with the contents of all parent POMs, user settings, and any active profiles. To see this “effective” POM, run the following command in the simple project’s base directory.

$ mvn help:effective-pom

When you run this, you should see a much larger POM which exposes the default settings of Maven. This goal can come in handy if you are trying to debug a build and want to see how all of the current project’s ancestor POMs are contributing to the effective POM.

3.5. Core Concepts

Having just run Maven for the first time, it is a good time to introduce a few of the core concepts of Maven. In the previous example, you generated a project which consisted of a POM and some code assembled in the Maven standard directory layout. You then executed Maven with a lifecycle phase as an argument, which prompted Maven to execute a series of Maven plugin goals. Lastly, you installed a Maven artifact into your local repository. Wait? What is a “lifecycle”? What is a “local repository”? The following section defines some of Maven’s central concepts.

3.5.1. Maven Plugins and Goals

To execute a single Maven plugin goal, we used the syntax mvn archetype:generate, where archetype is the identifier of a plugin and generate is the identifier of a goal. When Maven executes a plugin goal, it prints out the plugin identifier and goal identifier to standard output:

$ mvn archetype:generate -DgroupId=org.sonatype.mavenbook.simple
...
[INFO] [archetype:generate]
...

A Maven Plugin is a collection of one or more goals. Examples of Maven plugins can be simple core plugins like the Jar plugin, which contains goals for creating JAR files, Compiler plugin, which contains goals for compiling source code and unit tests, or the Surefire plugin, which contains goals for executing unit tests and generating reports. Other, more specialized Maven plugins include plugins like the Hibernate3 plugin for integration with the popular persistence library Hibernate, the JRuby plugin which allows you to execute ruby as part of a Maven build or to write Maven plugins in Ruby. Maven also provides for the ability to define custom plugins. A custom plugin can be written in Java, or a plugin can be written in any number of languages including Ant, Groovy, beanshell, and, as previously mentioned, Ruby.
simple-project_plugin.png
Figure 3.1. A Plugin Contains Goals

A goal is a specific task that may be executed as a standalone goal or along with other goals as part of a larger build. A goal is a “unit of work” in Maven. Examples of goals include the compile goal in the Compiler plugin, which compiles all of the source code for a project, or the test goal of the Surefire plugin, which can execute unit tests. Goals are configured via configuration properties that can be used to customize behavior. For example, the compile goal of the Compiler plugin defines a set of configuration parameters. When running the archetype:generate goal earlier in Section 3.2, “Creating a Simple Project” we passed the package parameter to the generate goal as org.sonatype.mavenbook. If we had omitted the package parameter, the package name would have defaulted to org.sonatype.mavenbook.simple.

Note

When referring to a plugin goal, we frequently use the shorthand notation: pluginId:goalId. For example, when referring to the generate goal in the Archetype plugin, we write archetype:generate.

Goals define parameters that can define sensible default values. In the archetype:generate example, we did not specify what kind of archetype the goal was to create on our command line; we simply passed in a groupId and an artifactId. Not passing in the type of artifact we wanted to create caused the generate goal to prompt us for input, the generate goal stopped and asked us to choose an archetype from a list. If you had run the archetype:create goal instead, Maven would have assumed that you wanted to generate a new project using the default maven-archetype-quickstart archetype. This is our first brush with convention over configuration. The convention, or default, for the create goal is to create a simple project called Quickstart. The create goal defines a configuration property archetypeArtifactId that has a default value of maven-archetype-quickstart. The Quickstart archetype generates a minimal project shell that contains a POM and a single class. The Archetype plugin is far more powerful than this first example suggests, but it is a great way to get new projects started fast. Later in this book, we’ll show you how the Archetype plugin can be used to generate more complex projects such as web applications, and how you can use the Archetype plugin to define your own set of projects.

The core of Maven has little to do with the specific tasks involved in your project’s build. By itself, Maven doesn’t know how to compile your code or even how to make a JAR file. It delegates all of this work to Maven plugins like the Compiler plugin and the Jar plugin, which are downloaded on an as-needed basis and periodically updated from the central Maven repository. When you download Maven, you are getting the core of Maven, which consists of a very basic shell that knows only how to parse the command line, manage a classpath, parse a POM file, and download Maven plugins as needed. By keeping the Compiler plugin separate from Maven’s core and providing for an update mechanism, Maven makes it easier for users to have access to the latest options in the compiler. In this way, Maven plugins allow for universal reusability of common build logic. You are not defining the compile task in a build file; you are using a Compiler plugin that is shared by every user of Maven. If there is an improvement to the Compiler plugin, every project that uses Maven can immediately benefit from this change. (And, if you don’t like the Compiler plugin, you can override it with your own implementation.)

3.5.2. Maven Lifecycle

The second command (mvn install) we ran in the previous section included an execution of the Maven lifecycle. It begins with a phase to validate the basic integrity of the project and ends with a phase that involves deploying a project to production. Lifecycle phases are intentionally vague, defined solely as validation, testing, or deployment, and they may mean different things to different projects. For example, in a project that produces a Java archive, the package phase produces a JAR; in a project that produces a web application, the package phase produces a WAR.

Plugin goals can be attached to a lifecycle phase. As Maven moves through the phases in a lifecycle, it will execute the goals attached to each particular phase. Each phase may have zero or more goals bound to it. In the previous section, when you ran mvn install, you might have noticed that more than one goal was executed. Examine the output after running mvn install and take note of the various goals that are executed. When this simple example reached the package phase, it executed the jar goal in the Jar plugin. Since our simple Quickstart project has (by default) a jar packaging type, the jar:jar goal is bound to the package phase.
simple-project_phasebinding.png
Figure 3.2. A Goal Binds to a Phase

We know that the package phase is going to create a JAR file for a project with jar packaging. But what of the goals preceding it, such as compiler:compile and surefire:test? These goals are executed as Maven steps in the phases preceding package in the Maven lifecycle.

  • resources:resources

    plugin is bound to the process-resources phase. This goal copies all of the resources from src/main/resources and any other configured resource directories to the output directory.

  • compiler:compile

    is bound to the compile phase. This goal compiles all of the source code from src/main/java or any other configured source directories to the output directory.

  • resources:testResources

    plugin is bound to the process-test-resources phase. This goal copies all of the resources from src/test/resources and any other configured test resource directories to a test output directory.

  • compiler:testCompile

    plugin is bound to the test-compile phase. This goal compiles test cases from src/test/java and any other configured test source directories to a test output directory.

  • surefire:test

    bound to the test phase. This goal executes all of the tests and creates output files that capture detailed results. By default, this goal will terminate a build if there is a test failure.

  • jar:jar

    to the package phase. This goal packages the output directory into a JAR file.

simple-project_lifecyclebinding.png
Figure 3.3. Bound Goals are Run when Phases Execute

To summarize, when we executed mvn install, Maven executes all phases up to the install phase, and in the process of stepping through the lifecycle phases it executes all goals bound to each phase. Instead of executing a Maven lifecycle goal you could achieve the same results by specifying a sequence of plugin goals as follows:

总而言之,当我们执行mvn install时,Maven会执行直到安装阶段的所有阶段,并且在逐步进入生命周期阶段的过程中,它将执行绑定到每个阶段的所有目标。 您可以通过指定一系列插件目标来实现相同的结果,而不是执行Maven生命周期目标:

mvn resources:resources \
    compiler:compile \
    resources:testResources \
    compiler:testCompile \
    surefire:test \
    jar:jar \
    install:install

It is much easier to execute lifecycle phases than it is to specify explicit goals on the command line, and the common lifecycle allows every project that uses Maven to adhere to a well-defined set of standards. The lifecycle is what allows a developer to jump from one Maven project to another without having to know very much about the details of each particular project’s build. If you can build one Maven project, you can build them all.

执行生命周期阶段要比在命令行上指定明确的目标要容易得多,并且通用生命周期允许使用Maven的每个项目遵守一组定义明确的标准。 生命周期使开发人员可以从一个Maven项目跳至另一个项目,而不必非常了解每个特定项目的构建细节。 如果可以构建一个Maven项目,则可以全部构建。

3.5.3. Maven Coordinates

The Archetype plugin created a project with a file named pom.xml. This is the Project Object Model (POM), a declarative description of a project. When Maven executes a goal, each goal has access to the information defined in a project’s POM. When the jar:jar goal needs to create a JAR file, it looks to the POM to find out what the JAR file’s name is. When the compiler:compile goal compiles Java source code into bytecode, it looks to the POM to see if there are any parameters for the compile goal. Goals execute in the context of a POM. Goals are actions we wish to take upon a project, and a project is defined by a POM. The POM names the project, provides a set of unique identifiers (coordinates) for a project, and defines the relationships between this project and others through dependencies, parents, and prerequisites. A POM can also customize plugin behavior and supply information about the community and developers involved in a project.

Archetype插件使用名为pom.xml的文件创建了一个项目。 这是项目对象模型(POM),是项目的声明性描述。 当Maven执行目标时,每个目标都可以访问项目的POM中定义的信息。 当jar:jar目标需要创建一个JAR文件时,它会向POM查找该JAR文件的名称。 当compile:compile目标将Java源代码编译为字节码时,它会向POM查找是否有用于编译目标的任何参数。 目标是在POM中执行的。 目标是我们希望对项目采取的行动,而项目由POM定义。 POM为项目命名,为项目提供一组唯一的标识符(坐标),并通过依赖项,父项和先决条件定义该项目与其他项目之间的关系。 POM还可以自定义插件行为,并提供有关项目所涉及的社区和开发人员的信息。

Maven coordinates define a set of identifiers which can be used to uniquely identify a project, a dependency, or a plugin in a Maven POM. Take a look at the following POM.

Maven坐标定义了一组标识符,这些标识符可用于唯一地标识Maven POM中的项目,依赖项或插件。 看一下以下POM。
simple-project_annopom.png
Figure 3.4. A Maven Project’s Coordinates

We’ve highlighted the Maven coordinates for this project: the groupId, artifactId, version and packaging. These combined identifiers make up a project’s coordinates. There is a fifth, seldom-used coordinate named classifier which we will introduce later in the book. You can feel free to ignore classifiers for now. Just like in any other coordinate system, a set of Maven coordinates is an address for a specific point in “space”. Maven pinpoints a project via its coordinates when one project relates to another, either as a dependency, a plugin, or a parent project reference. Maven coordinates are often written using a colon as a delimiter in the following format: groupId:artifactId:packaging:version. In the above pom.xml file for our current project, its coordinates are represented as mavenbook:my-app:jar:1.0-SNAPSHOT.

就像在任何其他坐标系中一样,一组Maven坐标是“空间”中特定点的地址。 当一个项目与另一个项目相关时,无论是作为依赖项,插件还是父项目引用,Maven都会通过其坐标来精确定位项目。

  • groupId

    The group, company, team, organization, project, or other group. The convention for group identifiers is that they begin with the reverse domain name of the organization that creates the project. Projects from Sonatype would have a groupId that begins with com.sonatype, and projects in the Apache Software Foundation would have a groupId that starts with org.apache.

    组,公司,团队,组织,项目或其他组。 组标识符的约定是,它们以创建项目的组织的反向域名开头。 来自Sonatype的项目将具有以com.sonatype开头的groupId,而Apache基金会中的项目将具有以org.apache开头的groupId。

  • artifactId

    A unique identifier under groupId that represents a single project.

    groupId下的唯一标识符,代表单个项目。

  • version

    A specific release of a project. Projects that have been released have a fixed version identifier that refers to a specific version of the project. Projects undergoing active development can use a special identifier that marks a version as a SNAPSHOT.

    项目的特定版本。 已发布的项目具有一个固定的版本标识符,该标识符引用该项目的特定版本。 正在进行积极开发的项目可以使用特殊的标识符来将版本标记为SNAPSHOT。

The packaging format of a project is also an important component in the Maven coordinates, but it isn’t a part of a project’s unique identifier. A project’s groupId:artifactId:version make that project unique; you can’t have a project with the same three groupId, artifactId, and version identifiers.

项目的包装格式也是Maven坐标中的重要组成部分,但它不是项目唯一标识符的一部分。 项目的groupId:artifactId:version使该项目唯一; 您的项目不能具有相同的三个groupId,artifactId和版本标识符。

  • packaging

    The type of project, defaulting to jar, describing the packaged output produced by a project. A project with packaging jar produces a JAR archive; a project with packaging war produces a web application.

    项目类型,默认为jar,描述项目产生的打包输出。 一个带有包装类型为jar的项目将产生一个JAR存档; 一个带有包装类型为war的项目将产生一个Web应用程序。

These four elements become the key to locating and using one particular project in the vast space of other “Mavenized” projects . Maven repositories (public, private, and local) are organized according to these identifiers. When this project is installed into the local Maven repository, it immediately becomes locally available to any other project that wishes to use it. All you must do is add it as a dependency of another project using the unique Maven coordinates for a specific artifact.

这四个要素成为在其他使用maven管理的项目的广阔空间中定位和使用一个特定项目的关键。 Maven仓库(公共,私有和本地)根据这些标识符进行组织。 当该项目安装到本地Maven仓库中后,它便立即成为希望使用它的任何其他项目在本地可用的依赖。 您所要做的就是使用该项目的唯一Maven坐标将其添加为另一个项目的依赖项。
simple-project_mavenspace.png
Figure 3.5. Maven Space is a Coordinate System of Projects

3.5.4. Maven Repositories

When you run Maven for the first time, you will notice that Maven downloads a number of files from a remote Maven repository. If the simple project was the first time you ran Maven, the first thing it will do is download the latest release of the Resources plugin when it triggers the resources:resource goal. In Maven, artifacts and plugins are retrieved from a remote repository when they are needed. One of the reasons the initial Maven download is so small (1.5 MiB) is due to the fact that Maven doesn’t ship with much in the way of plugins. Maven ships with the bare minimum and fetches from a remote repository when it needs to. Maven ships with a default remote repository location (https://repo1.maven.org/maven2) which it uses to download the core Maven plugins and dependencies.

Often you will be writing a project which depends on libraries that are neither free nor publicly distributed. In this case you will need to either setup a custom repository inside your organization’s network or download and install the dependencies manually. The default remote repositories can be replaced or augmented with references to custom Maven repositories maintained by your organization. There are multiple products available to allow organizations to manage and maintain mirrors of the public Maven repositories.

What makes a Maven repository a Maven repository? A repository is a collection of project artifacts stored in a directory structure that closely matches a project’s Maven coordinates. You can see this structure by opening up a web browser and browsing the central Maven repository at https://repo1.maven.org/maven2/. You will see that an artifact with the coordinates org.apache.commons:commons-email:1.1 is available under the directory /org/apache/commons/commons-email/1.1/ in a file named commons-email-1.1.jar. The standard for a Maven repository is to store an artifact in the following directory relative to the root of the repository:

/<groupId>/<artifactId>/<version>/<artifactId>-<version>.<packaging>

Maven downloads artifacts and plugins from a remote repository to your local machine and stores these artifacts in your local Maven repository. Once Maven has downloaded an artifact from the remote Maven repository it never needs to download that artifact again as Maven will always look for the artifact in the local repository before looking elsewhere. On Windows XP, your local repository is likely in C:\Documents and Settings\USERNAME\.m2\repository, and on Windows Vista, your local repository is in C:\Users\USERNAME\.m2\repository. On Unix systems, your local Maven repository is available in ~/.m2/repository. When you build a project like the simple project you created in the previous section, the install phase executes a goal which installs your project’s artifacts in your local Maven repository.

In your local repository, you should be able to see the artifact created by our simple project. If you run the mvn install command, Maven will install our project’s artifact in your local repository. Try it.

$ mvn install
...
[INFO] [install:install]
[INFO] Installing .../simple-1.0-SNAPSHOT.jar to \
~/.m2/repository/com/sonatype/maven/simple/1.0-SNAPSHOT/ \
simple-1.0-SNAPSHOT.jar
...

As you can see from the output of this command, Maven installed our project’s JAR file into our local Maven repository. Maven uses the local repository to share dependencies across local projects. If you develop two projects—project A and project B—with project B depending on the artifact produced by project A, Maven will retrieve project A’s artifact from your local repository when it is building project B. Maven repositories are both a local cache of artifacts downloaded from a remote repository and a mechanism for allowing your projects to depend on each other.

3.5.5. Maven’s Dependency Management

In this chapter’s simple example, Maven resolved the coordinates of the JUnit dependency junit:junit:3.8.1 to a path in a Maven repository /junit/junit/3.8.1/junit-3.8.1.jar. The ability to locate an artifact in a repository based on Maven coordinates gives us the ability to define dependencies in a project’s POM. If you examine the simple project’s pom.xml file, you will see that there is a section which deals with dependencies, and that this section contains a single dependency—JUnit.

A more complex project would contain more than one dependency, or it might contain dependencies that depend on other artifacts. Support for transitive dependencies is one of Maven’s most powerful features. Let’s say your project depends on a library that, in turn, depends on 5 or 10 other libraries (Spring or Hibernate, for example). Instead of having to track down all of these dependencies and list them in your pom.xml explicitly, you can simply depend on the library you are interested in and Maven will add the dependencies of this library to your project’s dependencies implicitly. Maven will also take care of working out conflicts between dependencies, and provides you with the ability to customize the default behavior and exclude certain transitive dependencies.

一个更复杂的项目将包含多个依赖关系,或者它可能包含依赖于其他工件的依赖关系。 对传递依存关系的支持是Maven最强大的功能之一。 假设您的项目依赖于一个库,而库又依赖于5或10个其他库(例如Spring或Hibernate)。 您不必依赖所有这些依赖关系并在pom.xml中显式列出它们,而只需依赖您感兴趣的库,Maven就会将该库的依赖关系隐式添加到项目的依赖关系中。 Maven还负责解决依赖关系之间的冲突,并使您能够自定义默认行为并排除某些可传递依赖关系。

Let’s take a look at a dependency which was downloaded to your local repository when you ran the previous example. Look in your local repository path under ~/.m2/repository/junit/junit/3.8.1/. If you have been following this chapter’s examples, there will be a file named junit-3.8.1.jar and a junit-3.8.1.pom file in addition to a few checksum files which Maven uses to verify the authenticity of a downloaded artifact. Note that Maven doesn’t just download the JUnit JAR file, Maven also downloads a POM file for the JUnit dependency. The fact that Maven downloads POM files in addition to artifacts is central to Maven’s support for transitive dependencies.

请注意,Maven不仅下载JUnit JAR文件,而且还下载Junit依赖项的POM文件。 Maven除了提供工件外还下载POM文件这一事实对于Maven支持传递依赖项至关重要。

When you install your project’s artifact in the local repository, you will also notice that Maven publishes a slightly modified version of the project’s pom.xml file in the same directory as the JAR file. Storing a POM file in the repository gives other projects information about this project, most importantly what dependencies it has. If Project B depends on Project A, it also depends on Project A’s dependencies. When Maven resolves a dependency artifact from a set of Maven coordinates, it also retrieves the POM and consults the dependencies POM to find any transitive dependencies. These transitive dependencies are then added as dependencies of the current project.

在本地存储库中安装项目的工件时,您还会注意到Maven在与JAR文件相同的目录中发布了该项目的pom.xml文件的稍作修改的版本。 在存储库中存储POM文件可为其他项目提供有关该项目的信息,最重要的是它具有哪些依赖性。 如果项目B依赖项目A,那么它也依赖于项目A的依赖关系。 当Maven从一组Maven坐标中解析依赖项工件时,它还会检索POM并查询依赖项POM以查找任何传递性依赖项。 然后将这些可传递依赖项添加为当前项目的依赖项。

A dependency in Maven isn’t just a JAR file; it’s a POM file that, in turn, may declare dependencies on other artifacts. These dependencies of dependencies are called transitive dependencies, and they are made possible by the fact that the Maven repository stores more than just bytecode; it stores metadata about artifacts.

Maven中的依赖关系不仅仅是JAR文件; 这是一个POM文件,进而可以声明对其他工件的依赖性。 这些依赖关系的依赖关系称为传递依赖关系,由于Maven存储库存储的不仅仅是字节码,还使它们成为可能。 它存储有关工件的元数据。
simple-project_depgraph.png
Figure 3.6. Maven Resolves Transitive Dependencies

In the previous figure, project A depends on projects B and C. Project B depends on project D, and project C depends on project E. The full set of direct and transitive dependencies for project A would be projects B, C, D, and E, but all project A had to do was define a dependency on B and C. Transitive dependencies can come in handy when your project relies on other projects with several small dependencies (like Hibernate, Apache Struts, or the Spring Framework). Maven also provides you with the ability to exclude transitive dependencies from being included in a project’s classpath.

在上图中,项目A依赖于项目B和C。项目B依赖于项目D,项目C依赖于项目E。项目A的直接和传递依赖项的完整集合将是项目B,C,D和 E,但项目A所要做的就是定义对B和C的依赖。当您的项目依赖于具有几个小依赖项的其他项目(例如Hibernate,Apache Struts或Spring Framework)时,传递依赖项会派上用场。 Maven还为您提供了将传递依赖项排除在项目的类路径之外的功能。

Maven also provides for different dependency scopes. The simple project’s pom.xml contains a single dependency —junit:junit:jar:3.8.1 — with a scope of test. When a dependency has a scope of test, it will not be available to the compile goal of the Compiler plugin. It will be added to the classpath for only the compiler:testCompile and surefire:test goals.

When you create a JAR for a project, dependencies are not bundled with the generated artifact; they are used only for compilation. When you use Maven to create a WAR or an EAR file, you can configure Maven to bundle dependencies with the generated artifact, and you can also configure it to exclude certain dependencies from the WAR file using the provided scope. The provided scope tells Maven that a dependency is needed for compilation, but should not be bundled with the output of a build. This scope comes in handy when you are developing a web application. You’ll need to compile your code against the Servlet specification, but you don’t want to include the Servlet API JAR in your web application’s WEB-INF/lib directory.

当您为项目创建JAR时,依赖项不会与生成的工件捆绑在一起;它们仅用于编译。 使用Maven创建WAR或EAR文件时,可以将Maven配置为将依赖项与生成的工件捆绑在一起,也可以使用提供的范围将其配置为从WAR文件中排除某些依赖项。 提供的作用域告诉Maven,编译需要依赖项,但不应将其与构建输出捆绑在一起。 当您开发Web应用程序时,此范围非常有用。 您需要根据Servlet规范编译代码,但不想在Web应用程序的WEB-INF / lib目录中包含Servlet API JAR。

3.5.6. Site Generation and Reporting

Another important feature of Maven is its ability to generate documentation and reports. In your simple project’s directory, execute the following command:

$ mvn site

This will execute the site lifecycle phase. Unlike the default build lifecycle that manages generation of code, manipulation of resources, compilation, packaging, etc., this lifecycle is concerned solely with processing site content under the src/site directories and generating reports. After this command executes, you should see a project web site in the target/site directory. Load target/site/index.html and you should see a basic shell of a project site. This shell contains some reports under “Project Reports” in the lefthand navigation menu, and it also contains information about the project, the dependencies, and developers associated with it under “Project Information.” The simple project’s web site is mostly empty, since the POM contains very little information about itself beyond its Maven coordinates, a name, a URL, and a single test dependency.

On this site, you’ll notice that some default reports are available. A unit test report communicates the success and failure of all unit tests in the project. Another report generates Javadoc for the project’s API. Maven provides a full range of configurable reports, such as the Clover report that examines unit test coverage, the JXR report that generates cross-referenced HTML source code listings useful for code reviews, the PMD report that analyzes source code for various coding problems, and the JDepend report that analyzes the dependencies between packages in a codebase. You can customize site reports by configuring which reports are included in a build via the pom.xml file.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值