Урок за Apache Maven

1. Въведение

Изграждането на софтуерен проект обикновено се състои от такива задачи като изтегляне на зависимости, поставяне на допълнителни буркани на пътя на класа, компилиране на изходния код в двоичен код, провеждане на тестове, опаковане на компилиран код в разгръщащи се артефакти като JAR, WAR и ZIP файлове и разполагане на тези артефакти към сървър на приложения или хранилище.

Apache Maven автоматизира тези задачи, като свежда до минимум риска от грешки на хората, като същевременно ръчно изгражда софтуера и разделя работата по компилиране и опаковане на нашия код от тази при изграждането на кода.

В този урок ще изследваме този мощен инструмент за описване, изграждане и управление на софтуерни проекти на Java, използвайки централна информация - Project Object Model (POM) - която е написана в XML.

2. Защо да използваме Maven?

Основните характеристики на Maven са:

  • проста настройка на проекта, която следва най-добрите практики: Maven се опитва да избегне колкото е възможно повече конфигурация, като предоставя шаблони за проекти (наречени архетипове )
  • управление на зависимости: включва автоматично актуализиране, изтегляне и валидиране на съвместимостта, както и докладване на затварянията на зависимостите (известни също като преходни зависимости)
  • изолиране между зависимостите на проекта и приставките: с Maven зависимостите на проекта се извличат от хранилищата на зависимостите, докато зависимостите на всеки приставка се извличат от хранилищата на приставките, което води до по-малко конфликти, когато приставките започват да изтеглят допълнителни зависимости
  • система за централно хранилище: зависимостите на проекта могат да бъдат заредени от локалната файлова система или публични хранилища, като Maven Central
За да научите как да инсталирате Maven във вашата система, моля, проверете този урок за Baeldung.

3. Обектен модел на проекта

Конфигурирането на проект на Maven се извършва чрез обектен модел на проект (POM) , представен от файл pom.xml . В ОРП описва проекта, управлява зависимости и конфигурира плъгини за изграждане на софтуера.

В ОРП също така определя характера на взаимоотношенията между модули от няколко модула проекти. Нека разгледаме основната структура на типичен POM файл:

 4.0.0 org.baeldung org.baeldung jar 1.0-SNAPSHOT org.baeldung //maven.apache.org   junit junit 4.12 test      //...    

Нека разгледаме по-отблизо тези конструкции.

3.1. Идентификатори на проекти

Maven използва набор от идентификатори, наричани още координати, за да идентифицира еднозначно проект и да посочи как трябва да бъде пакетиран артефактът на проекта:

  • groupId - уникално основно име на компанията или групата, създала проекта
  • artifactId - уникално име на проекта
  • версия - версия на проекта
  • опаковка - метод за опаковане (напр. WAR / JAR / ZIP )

Първите три от тях ( groupId: artifactId: version ) се комбинират, за да формират уникалния идентификатор и са механизмът, чрез който указвате кои версии на външни библиотеки (например JAR) ще използва вашият проект.

3.2. Зависимости

Тези външни библиотеки, които проектът използва, се наричат ​​зависимости. Функцията за управление на зависимостите в Maven осигурява автоматично изтегляне на тези библиотеки от централно хранилище, така че не е нужно да ги съхранявате локално.

Това е ключова характеристика на Maven и осигурява следните предимства:

  • използва по-малко място за съхранение, като значително намалява броя на изтеглянията от отдалечени хранилища
  • прави проверката на проекта по-бърза
  • осигурява ефективна платформа за обмен на двоични артефакти във вашата организация и извън нея, без да е необходимо всеки път да се изгражда артефакт от източник

За да декларирате зависимост от външна библиотека, трябва да предоставите groupId, artifactId и версията на библиотеката. Нека да разгледаме един пример:

 org.springframework spring-core 4.3.5.RELEASE 

Докато Maven обработва зависимостите, той ще изтегли библиотеката Spring Core във вашето местно хранилище на Maven.

3.3. Хранилища

Хранилище в Maven се използва за съхранение на артефакти на компилация и зависимости от различен тип. Локалното хранилище по подразбиране се намира в папката .m2 / repository под домашната директория на потребителя.

Ако в локалното хранилище са налични артефакт или приставка, Maven ги използва. В противен случай той се изтегля от централно хранилище и се съхранява в локалното хранилище. Централното хранилище по подразбиране е Maven Central.

Някои библиотеки, като сървъра JBoss, не са налични в централното хранилище, но са налични в алтернативно хранилище. За тези библиотеки трябва да предоставите URL адреса на алтернативното хранилище във файла pom.xml :

  JBoss repository //repository.jboss.org/nexus/content/groups/public/  

Моля, обърнете внимание, че можете да използвате множество хранилища във вашите проекти.

3.4. Имоти

Персонализираните свойства могат да ви помогнат да улесните четенето и поддръжката на вашия файл pom.xml . В класическия случай на използване бихте използвали персонализирани свойства, за да дефинирате версии за зависимостите на вашия проект.

Свойствата на Maven са заместители на стойност и са достъпни навсякъде в рамките на pom.xml, като се използва нотацията $ {name} , където name е свойството.

Да видим пример:

 4.3.5.RELEASE    org.springframework spring-core ${spring.version}   org.springframework spring-context ${spring.version}  

Сега, ако искате да надстроите Spring до по-нова версия, трябва само да промените стойността вътре вмаркер на свойствата и всички зависимости, използващи това свойство в техните таговете ще бъдат актуализирани.

Свойствата също често се използват за дефиниране на променливи на пътя на изграждане:

 ${project.build.directory}/tmp/   //... ${project.resources.build.folder} //... 

3.5. Изграждане

The build section is also a very important section of the Maven POM. It provides information about the default Maven goal, the directory for the compiled project, and the final name of the application. The default build section looks like this:

 install ${basedir}/target ${artifactId}-${version}  filters/filter1.properties  //... 

The default output folder for compiled artifacts is named target, and the final name of the packaged artifact consists of the artifactId and version, but you can change it at any time.

3.6. Using Profiles

Another important feature of Maven is its support for profiles. A profile is basically a set of configuration values. By using profiles, you can customize the build for different environments such as Production/Test/Development:

  production    //...      development  true     //...     

As you can see in the example above, the default profile is set to development. If you want to run the production profile, you can use the following Maven command:

mvn clean install -Pproduction

4. Maven Build Lifecycles

Every Maven build follows a specified lifecycle. You can execute several build lifecyclegoals, including the ones to compile the project’s code, create a package, and install the archive file in the local Maven dependency repository.

4.1. Lifecycle Phases

The following list shows the most important Maven lifecycle phases:

  • validate – checks the correctness of the project
  • compile – compiles the provided source code into binary artifacts
  • test – executes unit tests
  • package – packages compiled code into an archive file
  • integration-test – executes additional tests, which require the packaging
  • verify – checks if the package is valid
  • install – installs the package file into the local Maven repository
  • deploy – deploys the package file to a remote server or repository

4.2. Plugins and Goals

A Maven plugin is a collection of one or more goals. Goals are executed in phases, which helps to determine the order in which the goals are executed.

The rich list of plugins that are officially supported by Maven is available here. There is also an interesting article how to build an executable JAR on Baeldung using various plugins.

To gain a better understanding of which goals are run in which phases by default, take a look at the default Maven lifecycle bindings.

To go through any one of the above phases, we just have to call one command:

mvn 

For example, mvn clean install will remove the previously created jar/war/zip files and compiled classes (clean) and execute all the phases necessary to install new archive (install).

Please note that goals provided by plugins can be associated with different phases of the lifecycle.

5. Your First Maven Project

In this section, we will use the command line functionality of Maven to create a Java project.

5.1. Generating a Simple Java Project

In order to build a simple Java project, let's run the following command:

mvn archetype:generate -DgroupId=org.baeldung -DartifactId=org.baeldung.java -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

The groupId is a parameter indicating the group or individual that created a project, which is often a reversed company domain name. The artifactId is the base package name used in the project, and we use the standard archetype.

Since we didn't specify the version and the packaging type, these will be set to default values — the version will be set to 1.0-SNAPSHOT, and the packaging will be set to jar.

If you don't know which parameters to provide, you can always specify interactiveMode=true, so that Maven asks for all the required parameters.

After the command completes, we have a Java project containing an App.java class, which is just a simple “Hello World” program, in the src/main/java folder.

We also have an example test class in src/test/java. The pom.xml of this project will look similar to this:

 4.0.0 org.baeldung org.baeldung.java jar 1.0-SNAPSHOT org.baeldung.java //maven.apache.org   junit junit 4.1.2 test   

As you can see, the junit dependency is provided by default.

5.2. Compiling and Packaging a Project

The next step is to compile the project:

mvn compile

Maven will run through all lifecycle phases needed by the compile phase to build the project's sources. If you want to run only the test phase, you can use:

mvn test

Now let's invoke the package phase, which will produce the compiled archive jar file:

mvn package

5.3. Executing an Application

Finally, we are going to execute our Java project with the exec-maven-plugin. Let's configure the necessary plugins in the pom.xml:

 src   maven-compiler-plugin 3.6.1  1.8 1.8    org.codehaus.mojo exec-maven-plugin 1.5.0  org.baeldung.java.App    

The first plugin, maven-compiler-plugin, is responsible for compiling the source code using Java version 1.8. The exec-maven-plugin searches for the mainClass in our project.

To execute the application, we run the following command:

mvn exec:java

6. Multi-Module Projects

The mechanism in Maven that handles multi-module projects (also called aggregator projects) is called Reactor.

The Reactor collects all available modules to build, then sorts projects into the correct build order, and finally, builds them one by one.

Let's see how to create a multi-module parent project.

6.1. Create Parent Project

First of all, we need to create a parent project. In order to create a new project with the name parent-project, we use the following command:

mvn archetype:generate -DgroupId=org.baeldung -DartifactId=parent-project

Next, we update the packaging type inside the pom.xml file to indicate that this is a parent module:

pom

6.2. Create Submodule Projects

In the next step, we create submodule projects from the directory of parent-project:

cd parent-project mvn archetype:generate -DgroupId=org.baeldung -DartifactId=core mvn archetype:generate -DgroupId=org.baeldung -DartifactId=service mvn archetype:generate -DgroupId=org.baeldung -DartifactId=webapp

To verify if we created the submodules correctly, we look in the parent-project pom.xml file, where we should see three modules:

 core service webapp 

Moreover, a parent section will be added in each submodule’s pom.xml:

 org.baeldung parent-project 1.0-SNAPSHOT 

6.3. Enable Dependency Management in Parent Project

Dependency management is a mechanism for centralizing the dependency information for a muti-module parent project and its children.

When you have a set of projects or modules that inherit a common parent, you can put all the required information about the dependencies in the common pom.xml file. This will simplify the references to the artifacts in the child POMs.

Let's take a look at a sample parent's pom.xml:

   org.springframework spring-core 4.3.5.RELEASE  //...  

By declaring the spring-core version in the parent, all submodules that depend on spring-core can declare the dependency using only the groupId and artifactId, and the version will be inherited:

  org.springframework spring-core  //... 

Moreover, you can provide exclusions for dependency management in parent's pom.xml, so that specific libraries will not be inherited by child modules:

  org.springframework spring-context  

Finally, if a child module needs to use a different version of a managed dependency, you can override the managed version in child's pom.xml file:

 org.springframework spring-core 4.2.1.RELEASE 

Please note that while child modules inherit from their parent project, a parent project does not necessarily have any modules that it aggregates. On the other hand, a parent project may also aggregate projects that do not inherit from it.

For more information on inheritance and aggregation please refer to this documentation.

6.4. Updating the Submodules and Building a Project

We can change the packaging type of each submodule. For example, let's change the packaging of the webapp module to WAR by updating the pom.xml file:

war

Now we can test the build of our project by using the mvn clean install command. The output of the Maven logs should be similar to this:

[INFO] Scanning for projects... [INFO] Reactor build order: [INFO] parent-project [INFO] core [INFO] service [INFO] webapp //............. [INFO] ----------------------------------------- [INFO] Reactor Summary: [INFO] ----------------------------------------- [INFO] parent-project .................. SUCCESS [2.041s] [INFO] core ............................ SUCCESS [4.802s] [INFO] service ......................... SUCCESS [3.065s] [INFO] webapp .......................... SUCCESS [6.125s] [INFO] -----------------------------------------

7. Conclusion

В тази статия обсъдихме някои от най-популярните функции на инструмента за изграждане на Apache Maven.

Всички примери за код на Baeldung са изградени с помощта на Maven, така че можете лесно да проверите нашия уебсайт на проекта GitHub, за да видите различни конфигурации на Maven.