Apache Maven is a tool, primarily used for Java, to help solve two problems:
- Describe the software build process (compiling, testing, packaging, etc.).
- Manage the various dependencies (JAR libraries) associated with a project.
At the core of Maven are the various plugins which help with the build process. Each plugin will have one or more goals associated with it.
The build process is nothing but a sequential execution of several plugins (and the associated goals).
The following examples of some of the popular plugins should make the concept of plugins and goals clear.
As was mentioned earlier, to execute a plugin, one of its associated goals must be specified. The maven-compiler-plugin supports two goals. The first goal (namely, compile) is executed in the following way:
This will compile the main source code of your project (“src/main/java”) and place the compiled classes under the “target/classes” folder. You can change this default behaviour, but why would you? After all, Maven follows the philosophy of convention over configuration!
The second goal (namely, testCompile) is executed in the following way:
This will compile the test source code of your project (“src/test/java”) and place the compiled classes under the “target/test-classes”.
This plugin has only one goal which is executed as follows:
This will run the unit tests of your project, print the test result to the console and store a generated test report under “target/surefire-reports”.
Combining plugin goals
As can be seen above, a plugin (with a goal) can be run on a project to do some predefined job. Now, multiple plugins can be executed sequentially to create a build process. However, Maven allows one nifty feature, whereby multiple plugin goals can be executed using just one command.
mvn compiler:compile compiler:testCompile surefire:test
The above command will perform three operations:
- Compile the main source code.
- Compile the test source code.
- Run unit tests and generate a report.
How to manage executing multiple plugins?
As the number of plugin goals which need to be executed grows, so grows the chances of an error creeping into a long terminal command. If you look at the build process for different projects, it turns out, this process usually follows a pattern (for e.g., compilation, followed by unit testing, followed by packaging, etc.).
To streamline (and standardize) this build process, Maven provides the concept of build lifecycle.
Out of the box, Maven provides us with three build lifecycles: clean, default and site.
Each lifecycle is made up of a number of phases, and each phase can execute zero or more plugin goals.
We will concentrate on the two first two lifecycles: default lifecycle and clean lifecycle.
The default lifecycle has 23 phases associated with it. Each of these 23 phases can execute zero or multiple goals. These phases are executed sequentially, in a predefined order. Execution of a phase refers to execution of the plugin goals associated with it.
Some of the important phases (in the order they are executed) are:
- process-resources: Copies the main resources into the main output directory.
- compile: Compilation of main source code.
- process-test-resources: Copies the test resources into the test output directory.
- test-compile: Compilation of test source code.
- package: Package the compiled code into a distributable format (JAR, WAR, etc.).
- install: Install the package into your local M2 (maven repo).
- deploy: Copies the package to the remote repo.
The complete list of the 23 phases can be found here.
When you execute a phase of the default lifecycle, all the phases above it are also executed. For e.g., to execute the install phase, and all the phases above it, simply run the following command:
Maven, out of the box, binds some of these 23 phases to some plugin goals. So, when you execute mvn install (without associating any custom goal to any phase), the default phase goals are executed. These default goals are determined by the type of project packaging. For e.g., for the packaging type JAR these are the default bindings.
The clean lifecycle has only three phases: pre-clean, clean and post-clean.
The most important of these, clean, is executed as follows:
This phase has the maven-clean-plugin‘s clean goal associated with it. This goal clears the contents of the “target/” folder.
Lifecycles can be combined in the following manner:
mvn clean install
This command results in the following:
- The clean phase of the clean lifecyle is executed. Which in turn executes the clean goal of the maven-clean-plugin.
- The install phase of the default lifecycle is executed. Which results in 22 phases being executed (deploy phase is not executed since it comes after install in the execution hierarchy).
The build process of Maven is simply the execution of multiple plugin goals. To make this build process easier for developers, Maven provides the concept of lifecycles. Each lifecycle is a combination of multiple phases, and each phase can have multiple plugin goals associated with it.
This post turned out to be a bit longer than I expected. So, not going to dig deeper into the dependency management functionality of Maven. Also, I could not cover how plugin goals can be bound to lifecycle phases. I might cover these topics in a future post. Till then, you can play around with the various plugins offered by Maven. Cheers!