Maven Dependency Management
Enterprise-level projects typically depend on a variety of open source libraries. Consider the scenario where you want to use Log4J for your application logging. To accomplish this, you would go to the Log4J download page, download the JAR file, and put it in your project’s lib folder or add it to the project’s class path. As you may know already, there are a couple of problems with this approach:
To address these problems, Maven provides declarative dependency management. With this approach, you declare your project’s dependencies in an external file called pom.xml. Maven will automatically download those dependencies and hand them over to your project for the purpose of building, testing, or packaging.
Figure 3-1 shows a high-level view of Maven’s dependency management. As you can see, Maven interacts with repositories that hold artifacts and related metadata. Repositories that are typically accessed over the web are considered remote and are maintained by a third party. The default remote repository with which Maven interacts is called Maven Central, and it is located at repo.maven.apache.org and uk.maven.org. Maven places the downloaded artifacts in the local repository.
Figure 3-1. Maven dependency management
Although the architecture shown in Figure 3-1 works in the majority of cases, it poses a few problems in an enterprise environment. The first problem is that sharing company-related artifacts between teams is not possible. Because of security and intellectual property concerns, you wouldn’t want to publish your enterprise’s artifacts on Maven Central. Another problem concerns legal and licensing issues. Your company might want the teams only to use officially approved open source software, and this architecture would not fit in that model. The final issue concerns bandwidth and download speeds. In times of heavy load on Maven Central, the download speeds of Maven artifacts are reduced, and this might have a negative impact on your builds. Hence, most enterprises employ the architecture shown in Figure 3-2.
Figure 3-2. Enterprise Maven repository architecture
The internal repository manager acts as a proxy to remote repositories. Because you have full control over the internal repository, you can regulate the types of artifacts allowed in your company. Additionally, you can also push your organization’s artifacts onto the server, thereby enabling collaboration. There are several open source repository managers. Table 3-1 lists just some of them.
Table 3-1. Open Source Repository Managers
Repository Manager |
URL |
---|---|
Sonatype Nexus | www.sonatype.com/nexus |
Apache Archiva | |
Artifactory |
Using Repositories
In order to use a new repository, you need to modify the settings.xml file. Listing 3-1 shows Spring and JBoss repositories added to the settings.xml file. In this same way, you can add to your company’s repository manager.
Listing 3-1. Adding Repositories in settings.xml
<?xml version="1.0" encoding="UTF-8" ?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
.......
<profiles>
<profile>
<id>your_company</id>
<repositories>
<repository>
<id>spring_repo</id>
<url>http://repo.spring.io/release/</url>
</repository>
<repository>
<id>jboss_repo</id>
<url>https://repository.jboss.org/</url>
</repository>
</repositories>
</profile>
</profiles>
<activeProfiles>
<activeProfile>your_company</activeProfile>
</activeProfiles>
.......
</settings>
Note Information regarding repositories can be provided in the settings.xml or the pom.xml file. There are pros and cons to each approach. Putting repository information in the pom.xml file can make your builds portable. It enables developers to download projects and simply build them without any further modifications to their local settings.xml file. The problem with this approach is that when artifacts are released, the corresponding pom.xml files will have the repository information hard coded in them. If the repository URLs were ever to change, consumers of these artifacts will run into errors due to broken repository paths. Putting repository information in the settings.xml file addresses this problem, and because of the flexibility it provides, the settings.xml approach is typically recommended in an enterprise setting.
Maven dependencies are typically archives such as JAR, WAR, enterprise archive (EAR), and ZIP. Each Maven dependency is uniquely identified using the following group, artifact, and version (GAV) coordinates:
Dependencies declared in your project’s pom.xml file often have their own dependencies. Such dependencies are called transitive dependencies. Take the example of Hibernate Core. For it to function properly, it requires JBoss Logging, dom4j, javaassist, and so forth. The Hibernate Core declared in your pom.xml file is considered a direct dependency, and dependencies such as dom4j and javaassist are considered your project’s transitive dependencies. A key benefit of Maven is that it automatically deals with transitive dependencies and includes them in your project.
Figure 3-3 provides an example of transitive dependencies. Notice that transitive dependencies can have their own dependencies. As you might imagine, this can quickly get complex, especially when multiple direct dependencies pull different versions of the same JAR file.
Figure 3-3. Transitive dependencies
Maven uses a technique known as dependency mediation to resolve version conflicts. Simply stated, dependency mediation allows Maven to pull the dependency that is closest to the project in the tree. In Figure 3-3, there are two versions of dependency B: 0.0.8 and 1.0.0. In this scenario, version 0.0.8 of dependency B is included in the project, because it is a direct dependency and closest to the tree. Now look at the three versions of dependency F: 0.1.3, 1.0.0, and 2.2.0. All three dependencies are at the same depth. In this scenario, Maven will use the first-found dependency, which would be 0.1.3, and not the latest 2.2.0 version.
Note Although highly useful, transitive dependencies can cause problems and unpredictable side effects, as you might end up including unwanted JAR files or older versions of JAR files. Always analyze your dependency tree and make sure you are bundling the dependencies you need and excluding the ones you don’t require.
Consider a project that uses JUnit for its unit testing. The JUnit JAR file you included in your project is only needed during testing. You really don’t need to bundle the JUnit JAR in your final production archive. Similarly, consider the MySQL database driver, mysql-connector-java.jar file. You need the dependency when you are running the application inside a container such as Tomcat. Maven uses the concept of scope, which allows you to specify when and where you need a particular dependency.
Maven provides the following six scopes:
Manual Dependency Installation
Ideally, you will be pulling dependencies in your projects from public repositories or your enterprise repository manager. However, there will be times where you need an archive available in your local repository so that you can continue your development. For example, you might be waiting on your system administrators to add the required JAR file to your enterprise repository manager.
Maven provides a handy way of installing an archive into your local repository with the install plug-in. Listing 3-2 installs a test.jar file located in the c:apressgswm-bookchapter3 folder.
Listing 3-2. Installing Dependency Manually
C:apressgswm-bookchapter3>mvn install:install-file -DgroupId=com.apress.gswmbook -DartifactId=test -Dversion=1.0.0 -Dfile=C:apressgswm-bookchapter3 est.jar -Dpackaging=jar -DgeneratePom=true
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building Maven Stub Project (No POM) 1
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-install-plugin:2.4:install-file (default-cli) @ standalone-pom---
[INFO] Installing C:apressgswm-bookchapter3 est.jar to C:Users<<USER_NAME>>.m2 epositorycomapressgswmbook est1.0.0 est-1.0.0.jar
[INFO] Installing C:Users<<USER_NAME>>AppDataLocalTempmvninstall2668943665146984418.pom to C:Users<<USER_NAME>>.m2 epositorycomapressgswmbook est1.0.0 est-1.0.0.pom
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 0.470 s
[INFO] Finished at: 2014-10-24T20:23:36-06:00
[INFO] Final Memory: 4M/15M
After seeing the BUILD SUCCESS message, you can verify the installation by going to your local Maven repository, as shown in Figure 3-4.
Figure 3-4. Dependency added to repository
Summary
Dependency management is at the heart of Maven. Every nontrivial Java project relies on open source or external artifacts, and Maven’s dependency management automates the process of retrieving those artifacts and including them at the right stages of the build process. You also learned that Maven uses GAV coordinates to identify its artifacts.
In the next chapter, you will learn about the organization of a basic Maven project.
3.144.21.158