Article image
Thiago Sampaio
Thiago Sampaio06/09/2021 03:42
Compartilhe

Tutorial completo do Maven para iniciantes

  • #Maven

Se você é um desenvolvedor Java, suas atividades diárias enquanto trabalha em projetos Java incluem escrever código, compilar código, testar, empacotar código na forma de um artefato como JAR.

O Apache Maven automatiza todas as tarefas mencionadas acima, minimizando a sobrecarga manual.

Neste tutorial, vamos entender O que é Apache Maven? e irá cobrir todos os conceitos necessários para você começar a usar o Maven em seus projetos Java.

OBS: Material de Estudo no final do tutorial.

O que é Apache Maven?

Apache Maven é uma ferramenta de gerenciamento de projetos usada para gerenciar projetos que são desenvolvidos usando linguagens JVM como Java, Scala, Groovy etc.

As principais tarefas de uma ferramenta de gerenciamento de projetos incluem:

  • Construir o Código Fonte
  • Testar de código-fonte
  • Empacotar o código-fonte em um artefato (ZIP, JAR, WAR ou EAR)
  • Lidar com o controle de versão e releases dos artefatos
  • Gerar JavaDocs a partir do código-fonte
  • Gerenciar Dependências do Projeto

Maven também é chamado de ferramenta de construção ou ferramenta de gerenciamento de dependência.

Criando o primeiro projeto Maven via CLI

Para cria um projeto Maven, digite o comando abaixo e siga as instruções:

mvn archetype:generate

Explorando a estrutura de pastas do Maven

Vamos dar uma olhada na estrutura de pastas do projeto Maven que acabamos de criar.

A pasta src é a raiz do código-fonte e dos testes de nosso aplicativo. Então, temos as seguintes subpastas:

  • A pasta src/main/java contém o código-fonte java, todo o código de produção para nosso aplicativo reside aqui
  • No src/main/resources vamos armazenar todos os arquivos que vamos usar em nosso projeto (exemplo: Arquivos de propriedade, quaisquer arquivos que precisemos ler em nosso aplicativo como XML, CSV etc.). Se você estiver desenvolvendo um aplicativo da web, normalmente colocaremos todos os recursos estáticos dentro desta pasta.
  • Na pasta src/test/java , armazenaremos todas as classes de teste em nosso projeto.
  • Há outra pasta chamada target, que armazena os arquivos de classe java compilados.
  • E por último, temos o arquivo pom.xml que contém os metadados das dependências do projeto.

Conceitos básicos do Maven

Project Object Model (POM)

O arquivo Project Object Model do projeto (também chamado de pom.xml) contém os metadados do projeto e também é responsável por gerenciar dependências e configurar plug-ins que nos ajudam a automatizar muitas tarefas repetitivas.

Esta é a aparência de um arquivo pom.xml básico:

<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>org.example</groupId>
  <artifactId>maven-project</artifactId>
  <version>1.0-SNAPSHOT</version>  
</project>
  • project é a tag de nível superior de nosso arquivo pom.xml, que encapsula todas as informações relacionadas ao nosso projeto Maven.
  • modelVersion representa qual versão do POM você está usando. O modelVersion para Maven 3 é sempre 4.0. Isso nunca mudará, a menos que você esteja usando outra versão principal do Maven.

Agora, como sabemos o que é um arquivo POM, vamos dar uma olhada nos diferentes tipos de arquivos POM. Temos basicamente 3 tipos de arquivos POM:

  • Arquivo POM simples
  • Arquivo Super POM
  • Arquivo POM efetivo

Arquivo POM Simples

Este é o mesmo arquivo (pom.xml) que foi gerado na seção anterior. Ele contém apenas informações que são relevantes para o nosso projeto atual.

Arquivo Super POM

Um arquivo Super POM é o pai de todos os arquivos POM simples, ele contém um conjunto de configurações padrão que é compartilhado por todos os arquivos POM simples.

Você pode encontrar o arquivo Super POM dentro do diretório de instalação do Maven no caminho M2_HOME/lib e dentro do arquivo JAR maven-model-builder-XXX.jar, onde XXX representa a versão da versão maven que você está usando.

Podemos encontrá-lo com o nome de pacote org.apache.maven.model com o nome de arquivo pom-4.0.0.xml.

CUIDADO : Você nunca deve tentar editar o Super POM, pois ele contém padrões razoáveis do Maven.

Arquivo POM Efetivo

Um arquivo POM efetivo nada mais é do que uma combinação de arquivos POM simples e Super POM.

É apenas uma forma de verificar todas as informações dos arquivos pom.xml em um só lugar.

Você pode dar uma olhada no POM efetivo de nosso arquivo pom.xml digitando o seguinte comando:

mvn help:effective-pom

Dependências

Se você estiver trabalhando em qualquer projeto Java não trivial, é provável que esteja usando muitos arquivos JAR de terceiros em seu projeto para desenvolver o aplicativo. Esses arquivos JAR podem ser qualquer coisa como um Framework ou uma Biblioteca. Os exemplos incluem Junit, Spring Framework, Selenium etc.

Essas bibliotecas externas são chamadas de dependências. O Maven oferece uma excelente maneira de especificar e gerenciar dependências em nosso arquivo pom.xml.

Sem usar o Maven, você deve baixar manualmente os arquivos JAR necessários da Internet e adicioná-los um por um ao classpath do nosso projeto.

O Maven fornece uma seção de dependências dentro do pom.xml onde você pode especificar as informações do JAR que você precisa em seu projeto (groupId , artifactId e versão). Depois de especificar as bibliotecas necessárias, o maven baixará automaticamente essas dependências em nosso projeto e as adicionará ao classpath de nosso projeto.

Dentro da seção de dependências você pode definir cada dependência individual como abaixo dentro do arquivo pom.xml.

<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>org.example</groupId>
  <artifactId>maven-project</artifactId>
  <version>1.0-SNAPSHOT</version>

  <dependencies>
      <dependency>
          <groupId>org.junit.jupiter</groupId>
          <artifactId>junit-jupiter-engine</artifactId>
          <version>5.5.2</version>
      </dependency>
  </dependencies>
</project>

Definimos Junit5 como uma dependência em nosso arquivo pom.xml.

Observe as tags groupId, artifactId e version para identificar exclusivamente uma dependência e, ao fornecer esses valores, o Maven pode baixar automaticamente essas dependências para nosso projeto.

Dependências Transitivas

Dependências transitivas são aquelas que dependem de outra.

Excluindo Dependências

Para excluir dependências, basta removê-las do arquivo pom.xml.

<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>org.example</groupId>
  <artifactId>maven-project</artifactId>
  <version>1.0-SNAPSHOT</version>
</project>

Dependências SNAPSHOT e RELEASE

Uma dependência pode ser categorizada de duas maneiras:

  • SNAPSHOT
  • RELEASE

Se você estiver trabalhando em um projeto Java em uma equipe, é provável que esteja seguindo algum tipo de processo iterativo no qual passa pelas fases de desenvolvimento e, em seguida, libera o software no final da fase.

Quando o projeto está em desenvolvimento geralmente usamos as dependências SNAPSHOT, que se parecem com 1.0-SNAPSHOT

<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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>org.example</groupId>
  <artifactId>maven-project</artifactId>
  <version>1.0-SNAPSHOT</version>
</project>

Quando o software está pronto para o lançamento, geralmente criamos uma versão RELEASE que se parece com 1.0.RELEASE

<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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>org.example</groupId>
  <artifactId>maven-project</artifactId>
  <version>1.0.RELEASE</version>
</project>

Escopos de Dependência

Cada dependência Maven pode ser categorizada em 6 escopos diferentes.

Aqui está a lista de escopos disponíveis:

  • compile: este é o escopo padrão se nenhum for especificado. As dependências de tempo de compilação estão disponíveis no classpath do projeto.
  • provided: Semelhante ao escopo compile, mas indica que o JDK ou o contêiner subjacente fornecerá a dependência no tempo de execução. A dependência estará disponível no momento da compilação, mas não empacotada no artefato.
  • runtime: as dependências definidas com este escopo estarão disponíveis apenas em tempo de execução, mas não em tempo de compilação. Um exemplo de uso: Imagine se você estiver usando o driver MySQL dentro do seu projeto, você pode adicionar a dependência com escopo como tempo de execução, para garantir que a abstração da API JDBC seja usada em vez da API do driver MySQL durante a implementação. Se o código-fonte incluir qualquer classe que faça parte da API JDBC do MySQL, o código não será compilado, pois a dependência não está disponível no momento da compilação.
  • test: as dependências estão disponíveis apenas no momento da execução dos testes, exemplos típicos incluem Junit.
  • system: é semelhante ao escopo provided, mas a única diferença é que precisamos mencionar explicitamente onde a dependência pode ser encontrada no sistema, usando a tag systemPath:
<systemPath>${basedir}/lib/some-dependency.jar</systemPath>

Repositórios

As dependências são armazenadas em um diretório especial chamado Repositório. Existem basicamente 2 tipos de repositórios:

  • Local Repository Um Repositório local é um diretório na máquina onde o Maven está sendo executado.

O local padrão para o Repositório Local é ~/.m2 ou C:\Users<user-name>.m2\repository

  • Remote Repository Um Repositório remoto é um site onde podemos baixar dependências Maven. Pode ser um repositório fornecido pelo Maven (repo.maven.org) ou uma configuração de repositório customizada dentro de uma organização.

Agora vamos ver como o Maven resolve as dependências.

  • Quando você define uma dependência definida dentro do arquivo pom.xml, o Maven primeiro verifica se a dependência já está presente no Repositório Local ou não.
  • Se não estiver, ele tenta se conectar ao Repositório Remoto, (Ex: https://repo.maven.org) e tenta baixar as dependências e armazená-las dentro do Repositório Local. Podemos definir o Repositório Remoto em nosso pom.xml como abaixo:
<repositories>
<repository>
  <id>my-internal-site</id>
  <url>http://myserver/repo</url>
</repository>
</repositories>

Manipulação de versão Snapshot e Release

O Maven primeiro verifica o Repositório local antes de baixar uma dependência do Repositório remoto.

Ao lidar com dependências de SNAPSHOT, o Maven baixa periodicamente a dependência do Repositório Remoto, embora a dependência exista no Repositório Local.

Isso ocorre porque as dependências SNAPSHOT estão sob intenso desenvolvimento e estão sujeitas a alterações com freqüência.

Você pode alterar esse comportamento adicionando um seção dentro da tag de repositórios.

<repositories>
<repository>
  <id>my-internal-site</id>
  <url>http://myserver/repo</url>
  <snapshots>
      <enabled>true</enabled>
      <updatePolicy>XXX</updatePolicy>
  </snapshots>
</repository>
</repositories>

O valor XXX dentro da updatePolicy pode ser:

  • always: o Maven sempre verifica se há uma versão mais recente
  • daily: Este é o valor padrão, como o nome sugere, ele baixa a versão uma vez por dia na primeira execução.
  • interval:XXX: verifica a cada XXX minutos
  • never: nunca verifica as atualizações.

As versões RELEASE, por outro lado, são mais estáveis e seguem a resolução de dependência usual.

Ciclo de vida da versão Maven

Maven segue um ciclo de vida de build construir nosso projeto.

Este ciclo de vida é dividido em 3 partes:

  • default
  • clean
  • site

Cada ciclo de vida é independente um do outro e podem ser executados juntos.

O ciclo de vida padrão é dividido em diferentes fases, como a seguir:

  • validate: verifica se o arquivo pom.xml é válido ou não
  • compile: compila o código-fonte dentro do projeto
  • test: executa testes de unidade dentro do projeto
  • package: empacota o código-fonte em um artefato (ZIP, JAR, WAR ou EAR)
  • tintegration-test: executa testes marcados como testes de integração
  • verify: verifica se o pacote criado é válido ou não.
  • install: instala o pacote criado em nosso Repositório Local
  • deploy: implanta o pacote criado no Repositório Remoto

O ciclo de vida clean é principalmente responsável por limpar o .class e metadados gerados pelas fases de compilação acima.

A fase do ciclo de vida do site é responsável por gerar a documentação Java.

Todos os 3 ciclos de vida também contêm algumas fases adicionais, se você estiver interessado, pode consultar a documentação do Maven.

Plugins e Goals

Para poder executar essas fases do ciclo de vida, o Maven nos fornece plugins para realizar cada tarefa.

Cada plugin está associado a um objetivo específico.

Plugin de compilação Maven

O plug-in de compilação Maven é responsável por compilar nossos arquivos Java nos arquivos .class. É equivalente a executar javac.

Este plugin habilita a fase de compilação do ciclo de vida padrão.

Você pode adicionar este plug-in ao seu projeto adicionando a seção abaixo ao seu arquivo pom.xml na seção de dependências.

<build>
  <plugins>
      <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.8.1</version>
      </plugin>
  </plugins>
</build>

Após adicionar o plugin ao projeto, você pode ativar a fase de compilação , digitando o comando abaixo:

mvn compiler:compile

No comando acima o compiler é o nome do plugin e compile é o objetivo que inicia a fase do ciclo de vida - compile

Se você tiver alguns arquivos de teste, eles também serão compilados usando o plug-in do compilador com o comando abaixo:

mvn compiler:testCompile

Plugin Maven Surefire

O plugin Surefire gera relatórios de texto e XML na pasta target/surefire-reports.

Usando o plugin Surefire, podemos executar os testes dentro de nosso projeto usando o seguinte comando:

mvn test

O plug-in Surefire por padrão inclui todos os testes, se você tiver um monte de testes, você pode excluir manualmente alguns testes a serem executados usando a configuração abaixo:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-surefire-plugin</artifactId>
  <version>2.22.2</version>
  <configuration>
      <excludes>HelloWorldTest.java</excludes>
  </configuration>
</plugin>

Plugin de instalação do Maven

Ele é usado para empacotar nosso código-fonte em um artefato de nossa escolha como um JAR e instalá-lo em nosso Repositório local que é a pasta /.m2/repository.

Você pode configurar o plugin de instalação do Maven adicionando o código a seguir:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-install-plugin</artifactId>
  <version>2.5.2</version>
</plugin>

Você pode executar a fase de instalação do ciclo de vida digitando o comando abaixo:

mvn install

A fase de instalação inclui também as fases anteriores do ciclo de vida, portanto, como parte desta fase maven:

  • valida nosso pom.xml (validate)
  • compila nosso código fonte (compile)
  • executa nossos testes (test)
  • empacota nosso código-fonte em JAR (pacckage)
  • instala o JAR em nosso repositório local (install)

Plugin Maven Clean

Outro plugin importante no Maven é o plugin Maven Clean. Ao executar as fases do ciclo de vida acima, os arquivos gerados são armazenados em uma pasta chamada destino.

Normalmente, ao construir nosso código-fonte, precisamos começar do zero para que não haja inconsistências nos arquivos de classe ou JAR gerados.

Por esta razão, temos a fase de limpeza, em que deletaremos todo o conteúdo da pasta de destino. Você pode executar esta fase digitando os comandos abaixo:

mvn clean

Outros plugins Maven

Existem muitos outros plug-ins no mundo Maven, para executar outras fases no ciclo de vida de compilação do Maven, você pode verificá-los aqui

Usando Profiles

Os perfis podem ser usados no Maven para criar configurações de construção personalizadas. Isso significa personalizar o comportamento de nossas construções com base em condições específicas.

Por exemplo: Às vezes, precisamos testar se o pacote do código-fonte está funcionando corretamente ou não; nesse caso, podemos pular a execução do teste ativando a propriedade skip.tests como a seguir:

<profile>
  <id>skip-tests</id>
  <properties>
      <maven.test.skip>true</maven.test.skip>
  </properties>
</profile>

Agora podemos tentar executar a construção especificando qual perfil ativar usando o sinalizador -P .

mvn -Pskip-tests clean install

Este é apenas um uso simples dos perfis, você pode configurar vários perfis em nosso projeto para personalizar o comportamento de construção.

Projetos Maven Multi Módulo

No mundo real, onde estamos construindo alguns projetos não triviais, o código-fonte será modularizado e dividido em diferentes subprojetos.

Para gerenciar isso de forma eficaz, o Maven nos fornece projetos de vários módulos, onde você pode aninhar projetos diferentes uns dentro dos outros. Basicamente, estamos criando um relacionamento pai-filho entre diferentes projetos Maven.

Basicamente, temos um projeto pai (POM pai) que contém diferentes subprojetos (submódulos), cada um dos quais é novamente um projeto Maven normal.

O POM pai geralmente encapsula o POM de outros filhos e é por isso que é empacotado como um POM em vez do formato de embalagem normal como JAR.

O Super POM, por exemplo, é basicamente um tipo de POM pai que encapsula as configurações padrão definidas pelo Maven para nós.

Criando um Projeto Filho

Para criar um projeto filho, basta criar uma pasta com o nome do projeto e digitar o mesmo comando de criar um projeto maven.

Agora, se você abrir o pom.xml na pasta raiz, poderá observar as seguintes tags que são adicionadas ao criar o módulo maven.

<modules>
  <module>child-project-1</module>
</modules>

Podemos criar vários projetos da mesma maneira e você pode ver que todos os módulos serão listados um por um na tag de modules.

E se você verificar o pom.xml de child-project-1, você pode ver que o projeto raiz está configurado como um projeto pai.

<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
  <parent>
      <artifactId>maven-project</artifactId>
      <groupId>org.example</groupId>
      <version>1.0-SNAPSHOT</version>
  </parent>
  <modelVersion>4.0.0</modelVersion>

  <artifactId>child-project-1</artifactId>
</project>

Agora você pode construir todos os projetos de uma vez, executando o mvn install no projeto pai, e o Maven verifica todos os POMs e constrói todos eles um por um.

O Maven usa algo chamado Reactor, que é responsável por fazer a varredura de todo o projeto e identificar os projetos pai e filho do maven. Se houver alguma dependência, o Reactor garante a execução dos projetos na ordem necessária.

Por exemplo, se child-project-2 for dependente de child-project-3, então o Maven Reactor se certificará de primeiro construir child-project-3 e, em seguida, child-project-2.

Gerenciando dependências dentro do projeto Maven Multi Module

Quando você está trabalhando com vários módulos Maven, pode estar trabalhando com diferentes dependências em diferentes módulos e é provável que esteja usando dependências semelhantes em vários módulos.

O Maven nos fornece uma maneira de gerenciar efetivamente as dependências em seu projeto, permitindo-nos definir as dependências em um local centralizado (projeto pai) e usar essas dependências nos diferentes projetos filhos.

Isso minimiza a incompatibilidade de versão de dependência em vários projetos, pois temos um único local onde podemos gerenciar todas as dependências e suas versões.

Para gerenciar dependências, temos a seção dependencyManagement dentro do pom.xml e cada projeto filho pode escolher a dependência de que precisa.

<dependencyManagement>
  <dependencies>
      <dependency>
          <groupId>org.junit.jupiter</groupId>
          <artifactId>junit-jupiter-engine</artifactId>
          <version>5.5.2</version>
      </dependency>
  </dependencies>
</dependencyManagement>

Gerenciando Plugins dentro do Projeto Maven Multi Module

Também podemos gerenciar Plugins dentro de nosso projeto Maven Multi Module, semelhante às dependências.

Para gerenciar plugins, temos a seção pluginManagement dentro do pom.xml e cada projeto filho pode escolher o plugin de que precisa.

<pluginManagement>
  <plugins>
      <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.8.1</version>
          <configuration>
              <source>11</source>
              <target>11</target>
          </configuration>
      </plugin>
  </plugins>
</pluginManagement>

Material de Estudo

Artigo original em inglês: Maven Complete Tutorial for Beginners

Vídeo em português: Apache Maven para programadores Java iniciantes

Vídeo em inglês: Maven Complete Tutorial with IntelliJ

Vídeo em Espanhol: TUTORIAL JAVA - Multi Modules Projects con Maven

Compartilhe
Comentários (1)
Edson Gallo
Edson Gallo - 06/09/2021 09:38

Parabéns! Artigos como esse são importantes para complementar e dar a base teórica do que aprendemos aqui na prática e que, muitas vezes, é passado bem superficialmente.