Maven: Unveiling the Power of Build Automation
What is Maven
Maven is a tool to build source code and produce an artifact/output from an application.
Dependency management is the foremost reason for using Maven.
Why is it needed
Repeatable builds - Recreate our build for any environment
Transitive dependencies - Downloading dependencies will also pull all the other items it needs
Works with local repository - historically we had to download the same jar which could be used in multiple projects. What happens if i have 25 projects and the same jar is required ? Maven helps to reduce the disk-space and overhead involved
Maven Vs Ant
Maven | Ant |
Black box - don't see where everything is defined | Clear and straight forward - can see the steps |
A build tool | A scripting tool |
Steeper learning curve | Quicker to learn |
Convention over Configuration | Issues occur if we forget to change a variable or something inherited |
A simple maven Structure
If you head over to start.spring.io and then create a project with just the web dependency then you would get a pom.xml file like the below
groupId - Package Name (business/application name)
artifactId - Name of our application
version - Release
packaging - Distribution (war/jar/ear etc. )
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
<groupId>com.learning</groupId>
<artifactId>spring-security</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
</project>
Project Structure using Maven
- By default, Maven looks for src/main/java directory in any project.
It compiles all our code into a target directory and gets the required information from the pom.xml file.
Maven Goals
clean - deletes the target directory and any of its generated source code
compile - compile all the source code, generate source code based on the dependencies present in the project (Lombok for example)
package - runs the compile goal first, run any unit test inside the pom and bundle into the desired packaging type (jar/war/ear)
install - runs the package command first and then copy it in the local repository. It copies jar/war file or however its packaged & placed inside of your local repository. The default local repository -> home_directory/.m2
deploy - doesn't mean to deploy into an app server. It runs the install command and then deploy into a remote repository.
Maven Dependencies
To add a dependency into our application, we simply need 3 things as seen in the Maven structure section.
groupId
artifactId
version
A note about transitive dependency - If we add a dependency then all the required dependencies would be downloaded along with that one.
Example : - if we're working with spring-boot-starter-test then junit and mockito dependencies come as transitive dependencies (i.e.) there is no need to download them separately.
Tip - Never deploy a release to production if it has SNAPSHOT in it as its not possible to reproduce/recreate the code. It is just for development purpose.
If we do something as type "pom" then all of the dependencies present inside the pom are downloaded into our application and they are referred as "Depedency Pom" or Bill of Materials.
Scopes
compile - default scope & all of my resources are available everywhere inside my application
provided - dependency is not needed at compile time & provided by the runtime environment (say a container)
runtime - needed for execution, libraries like JDBC jars to connect to a database.
test - not included in the final package, junit jars is a good example.
system - hardcode a physical path to a jar which is brittle and better to avoid
import - deals with dependency management (i.e.) sharing resources across multiple pom files.
Dependency Repository
It is where the dependencies are downloaded
Can contain releases/snapshots or both
Goals
Goals are actually just plugins configured in the maven install
Super pom has all the goals defined - clean, compile, test, package, install, deploy
Inherently added to the effective pom (project pom)
Create a multi module project
Right Click on IDE's project Window -> Select Module -> Enter the required details
Module window doesn't come up if we right click on a file
The pom.xml file inside the multi-module project would refer the existing project's parent pom file.
In case of a multi-module project, Maven takes care of which one to build and the required dependencies.
BOM
Can be used to specify the type of BOM
Explicitly define specified versions for your sub-projects or your imported pom's
Can use as an independent file and utilise for dependency management part.
The 2 differences with POM file are
packaging type set to BOM
dependencyManagement tag is used
inherited classes can just use the version specified in the parent pom without specifying the version)
For example, if a parent pom has specified the version for hibernate then the child pom file don't need to specify the version and can just inherit from the parent pom which is what we call as "BOM" or bill of materials.
Like Java, Maven also supports Single Inheritance (i.e.) a child can inherit from only one parent. If there is a need to use another dependency from a different parent, then can make use of type & scope inside dependency tag
<type>pom</type>
<scope>import</scope>
Real world example: Also, in most of the spring boot projects we need to have a spring-boot-starter-parent individually but if the starter is available in the parent pom then using BOM, it can be used in all the child pom files instead of downloading.