Pular para o conteúdo

Maven, o nosso orquestrador

Maven: o que é e por que todo desenvolvedor Java deveria conhecê-lo

Seção intitulada “Maven: o que é e por que todo desenvolvedor Java deveria conhecê-lo”

Provavelmente já encontrou um arquivo chamado pom.xml em algum projeto.

Talvez também tenha visto comandos como:

Janela do terminal
mvn clean install

ou:

Janela do terminal
mvn spring-boot:run

Mas afinal, o que é o Maven?

De forma simples, o Apache Maven é uma ferramenta de automação de build e gerenciamento de projetos Java. Ele ajuda a baixar bibliotecas, compilar o código, executar testes, empacotar a aplicação e até publicar artefatos.

Mas essa definição ainda não explica por que ele é tão presente no ecossistema Java.

Para entender isso, precisamos voltar um pouco.


Imagine que você está criando uma API Java.

Seu projeto precisa de:

  • Spring Boot - Facilita a criação de aplicações independentes;

  • PostgreSQL - Gerenciamento de banco de dados relacional;

  • JUnit - Framework padrão para testes unitários em Java;

  • Mockito - Biblioteca de simulação para Java;

  • Jackson - Biblioteca Java para processamento de dados JSON;

  • Hibernate - Framework de mapeamento (ORM) para Java.

Todas essas bibliotecas são arquivos .jar.

Sem uma ferramenta de gerenciamento de dependências, você teria que:

  1. procurar cada biblioteca;

  2. baixar os arquivos .jar;

  3. colocá-los no projeto;

  4. descobrir quais outras bibliotecas elas precisam;

  5. resolver conflitos entre versões;

  6. configurar o classpath;

  7. repetir tudo isso quando alguma biblioteca fosse atualizada.

E aqui aparece um problema ainda maior.

Imagine que o Spring Boot dependa de uma biblioteca A, que depende da biblioteca B, que depende da biblioteca C.

Você realmente quer descobrir e baixar todas essas dependências manualmente?

É justamente nesse tipo de situação que o Maven começa a fazer sentido.

Uma biblioteca, no sentido geral, é uma coleção de classes que fornecem ferramentas para que você, como desenvolvedor, não precise escrever essas ferramentas.


O Apache Maven é uma ferramenta de build para projetos Java.

Segundo a própria documentação do projeto, ele utiliza um Project Object Model (POM) para gerenciar aspectos como compilação, testes e documentação do projeto.

Na prática, o Maven ajuda a padronizar tarefas que aparecem constantemente no desenvolvimento Java:

Código-fonte
↓
Compilação
↓
Testes
↓
Empacotamento
↓
Artefato

Por exemplo, uma aplicação pode terminar como:

meu-projeto.jar

O Maven consegue cuidar de grande parte desse processo.

Mas talvez a funcionalidade mais conhecida seja outra:

Gerenciar as dependências do projeto.


Quando você cria um projeto Maven, um dos arquivos mais importantes é:

pom.xml

POM significa:

Project Object Model

Ele é o arquivo central de configuração do Maven.

É nele que podemos definir informações como:

  • nome do projeto;

  • versão;

  • Java utilizado;

  • dependências;

  • plugins;

  • tipo de empacotamento;

  • configurações de build;

  • informações do projeto.

Um exemplo simples:

<project>
<modelVersion>4.0.0</modelVersion>
<groupId>br.com.exemplo</groupId>
<artifactId>minha-api</artifactId>
<version>1.0.0</version>
</project>

Esse arquivo funciona como uma espécie de contrato do projeto com o Maven.

O Maven lê o pom.xml e, a partir dessas informações, sabe como trabalhar com o projeto.


Você provavelmente verá esses três elementos em praticamente todo projeto Maven.

<groupId>br.com.exemplo</groupId>
<artifactId>minha-api</artifactId>
<version>1.0.0</version>

Eles identificam o projeto.

Normalmente representa a organização ou grupo responsável pelo projeto.

Por exemplo:

<groupId>com.google.guava</groupId>

ou:

<groupId>br.com.salvaai</groupId>

É o nome do artefato/projeto.

Por exemplo:

<artifactId>minha-api</artifactId>

Representa a versão:

<version>1.0.0</version>

Juntos, esses valores formam as chamadas coordenadas Maven de um artefato.


Agora chegamos a uma das partes mais importantes.

Suponha que nossa aplicação precise do Spring Web.

Em vez de baixar manualmente um .jar, podemos declarar a dependência no pom.xml:

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>3.5.6</version>
</dependency>
</dependencies>

A partir disso, o Maven consegue resolver e baixar a dependência necessária.

E existe uma característica extremamente importante:

Imagine:

Minha aplicação
↓
Biblioteca A
↓
Biblioteca B
↓
Biblioteca C

Se a Biblioteca A precisa da Biblioteca B, que por sua vez precisa da Biblioteca C, o Maven consegue resolver essas dependências transitivamente.

Ou seja, você não precisa declarar manualmente cada biblioteca necessária por suas dependências.

É uma das razões pelas quais gerenciar projetos Java grandes seria muito mais trabalhoso sem uma ferramenta como o Maven.


Você pode imaginar que existe uma enorme biblioteca online contendo milhares de artefatos Java.

Esse papel é desempenhado principalmente pelo Maven Central Repository, um dos principais repositórios públicos de dependências do ecossistema Java.

Quando você adiciona uma dependência ao pom.xml, o Maven procura o artefato nos repositórios configurados e pode armazená-lo no seu repositório local.

Por isso, depois de baixar uma dependência uma vez, ela normalmente não precisa ser baixada novamente para cada projeto.

O fluxo pode ser entendido assim:

pom.xml
↓
Maven
↓
Repositório remoto
↓
Dependência
↓
Repositório local
↓
Projeto

O Maven mantém um repositório local na máquina do desenvolvedor.

No Linux e macOS, normalmente ele fica em:

~/.m2/repository

No Windows:

C:\Users\SEU_USUARIO\.m2\repository

Imagine que você utilize:

<artifactId>junit-jupiter</artifactId>

Depois que o Maven baixa essa dependência, ela fica disponível no repositório local.

Isso também ajuda a evitar downloads desnecessários.


Outra ideia fundamental do Maven é o Build Lifecycle.

Em vez de cada projeto inventar seus próprios comandos e etapas de build, o Maven possui ciclos de vida padronizados.

O ciclo default, por exemplo, possui várias fases.

Algumas das mais conhecidas são:

validate
↓
compile
↓
test
↓
package
↓
verify
↓
install
↓
deploy

Cada fase representa uma etapa do processo de construção do projeto.

Vamos entender algumas delas.

Compila o código-fonte.

Janela do terminal
mvn compile

Executa os testes.

Janela do terminal
mvn test

Empacota a aplicação.

Por exemplo:

target/
└── minha-api-1.0.0.jar

Com:

Janela do terminal
mvn package

Além de construir o artefato, instala o resultado no repositório local.

Janela do terminal
mvn install

Pode publicar o artefato em um repositório remoto configurado.

Janela do terminal
mvn deploy

Essas fases são executadas em sequência.

Por exemplo, quando você executa:

Janela do terminal
mvn package

o Maven não executa apenas package.

Ele passa pelas fases anteriores necessárias:

validate
↓
compile
↓
test
↓
package

Isso torna o processo de build previsível e padronizado.


Você provavelmente encontrará esse comando em praticamente qualquer projeto Java baseado em Maven:

Janela do terminal
mvn clean install

Mas o que ele faz?

Primeiro:

Janela do terminal
mvn clean

Remove os arquivos gerados pelo build anterior.

Normalmente isso significa remover a pasta:

target/

Depois:

Janela do terminal
mvn install

Executa o ciclo necessário até instalar o artefato no repositório local.

Simplificando:

clean
↓
remove build anterior
↓
compile
↓
test
↓
package
↓
install

É uma maneira bastante comum de garantir que o projeto seja reconstruído do zero.


Se você executar:

Janela do terminal
mvn package

provavelmente verá uma pasta:

target/

Ela contém arquivos gerados pelo Maven durante o processo de build.

Por exemplo:

target/
├── classes/
├── test-classes/
├── surefire-reports/
└── minha-api-1.0.0.jar

Essa pasta normalmente não deve ser versionada no Git.

Por isso, projetos Java geralmente possuem no .gitignore:

target/

O Maven não faz tudo sozinho.

Grande parte de sua funcionalidade é fornecida através de plugins.

Por exemplo, existem plugins responsáveis por tarefas como:

  • compilação;

  • testes;

  • empacotamento;

  • documentação;

  • análise de dependências;

  • execução de aplicações.

Isso torna o Maven extensível.

Por exemplo, o processo de compilação pode utilizar o Maven Compiler Plugin.

Já os testes unitários podem ser executados pelo Maven Surefire Plugin.

Na documentação oficial, as fases do lifecycle possuem bindings que associam determinadas fases a goals de plugins.


Maven não é apenas um gerenciador de dependências

Seção intitulada “Maven não é apenas um gerenciador de dependências”

É comum alguém dizer:

“Maven é o gerenciador de dependências do Java.”

Não está totalmente errado, mas é uma definição incompleta.

O Maven também é responsável por automatizar o processo de build.

Podemos pensar nele como:

Maven
│
┌──────────┼──────────┐
↓ ↓ ↓
Dependências Build Testes
│ │ │
↓ ↓ ↓
Bibliotecas JAR/WAR JUnit etc.

Ele também possui mecanismos para documentação, publicação de artefatos, projetos multimódulo e gerenciamento de informações do projeto.


Uma dúvida comum é:

“Mas o Java já não possui um compilador?”

Sim.

O Java possui o javac, responsável por compilar código Java.

Por exemplo:

Janela do terminal
javac Main.java

O problema é que um projeto real normalmente envolve muito mais coisas.

Você precisa:

  • organizar o projeto;

  • encontrar dependências;

  • configurar o classpath;

  • compilar dezenas ou centenas de arquivos;

  • executar testes;

  • empacotar o resultado;

  • controlar versões;

  • eventualmente publicar o artefato.

O Maven automatiza esse conjunto de tarefas.

Em outras palavras:

javac
↓
compila Java

Enquanto:

Maven
↓
organiza e automatiza o processo de build

O Maven inclusive utiliza plugins para realizar determinadas etapas, como a compilação.


Outra vantagem do Maven é a padronização.

Um projeto costuma seguir uma estrutura parecida com:

meu-projeto/
│
├── pom.xml
│
└── src/
├── main/
│ ├── java/
│ └── resources/
│
└── test/
├── java/
└── resources/

Código da aplicação:

src/main/java

Recursos:

src/main/resources

Testes:

src/test/java

Testes e recursos possuem uma estrutura paralela à aplicação.

Isso significa que, ao abrir um projeto Maven novo, você não precisa descobrir do zero onde cada coisa está.

O próprio Maven estabelece convenções para essa estrutura.


Se você está estudando Java para desenvolvimento backend, provavelmente encontrará Maven principalmente através do Spring Boot.

Ao criar uma aplicação Spring Boot, é comum receber um pom.xml semelhante a:

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.5.6</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

Perceba algo interessante.

Em muitos casos, você nem precisa informar a versão individualmente de cada dependência.

Isso acontece porque o projeto pode utilizar um parent POM ou mecanismos como dependencyManagement para centralizar versões e configurações.


Se você está começando com Maven, estes comandos já cobrem uma boa parte do seu dia a dia:

Janela do terminal
mvn compile
Janela do terminal
mvn test
Janela do terminal
mvn package
Janela do terminal
mvn clean
Janela do terminal
mvn clean package
Janela do terminal
mvn clean install
Janela do terminal
mvn dependency:tree

Esse último é especialmente útil quando você começa a enfrentar conflitos de versões entre bibliotecas.

O próprio Maven disponibiliza o dependency:tree para visualizar a árvore de dependências resolvida.


Não.

Mais importante do que decorar comandos é entender o modelo mental do Maven.

Quando você vê:

Janela do terminal
mvn clean package

deve conseguir interpretar:

“Quero limpar os arquivos gerados anteriormente e executar o processo de build até gerar o pacote.”

Quando vê:

Janela do terminal
mvn dependency:tree

deve pensar:

“Quero descobrir quais dependências meu projeto está utilizando e de onde elas vieram.”

E quando abre:

pom.xml

deve pensar:

“Aqui está a definição e boa parte da configuração do meu projeto Maven.”


Imagine que você abriu um restaurante.

Você poderia:

  • comprar todos os ingredientes manualmente;

  • procurar fornecedores;

  • controlar estoque;

  • calcular o que precisa ser comprado;

  • preparar os ingredientes;

  • organizar a cozinha;

  • preparar os pratos;

  • limpar tudo no final.

Ou poderia utilizar um sistema que organiza boa parte desse processo.

O Maven é parecido com esse sistema para um projeto Java.

Você declara:

“Meu projeto precisa dessas ferramentas e bibliotecas.”

E o Maven cuida de grande parte da infraestrutura necessária para transformar:

Código-fonte

em:

Aplicação pronta para ser executada/distribuída

Não.

Java não depende do Maven para funcionar.

Existem outras alternativas, como o Gradle, além de ferramentas e abordagens diferentes.

O Maven, porém, tornou-se uma ferramenta extremamente difundida no ecossistema Java e aparece em uma enorme quantidade de projetos.

Por isso, para quem está entrando no desenvolvimento Java profissional, entender Maven é muito mais importante do que simplesmente saber executar mvn clean install.

O objetivo é entender o que está acontecendo por trás do comando.


Se você está começando agora, não precisa estudar toda a documentação do Maven.

Comece entendendo estes conceitos:

1. O que é o Maven
↓
2. O que é o pom.xml
↓
3. Dependências
↓
4. Dependências transitivas
↓
5. Repositório local
↓
6. Maven Central
↓
7. Build Lifecycle
↓
8. Plugins
↓
9. Packaging
↓
10. dependencyManagement

Depois disso, ferramentas como Spring Boot, Docker e pipelines de CI/CD começam a fazer muito mais sentido, porque você entende onde o Maven se encaixa dentro do processo de desenvolvimento.


O Maven nasceu de uma necessidade bastante prática: padronizar e simplificar o processo de construção de projetos Java. Desde então, tornou-se uma das ferramentas fundamentais do ecossistema.

Ele não serve apenas para baixar bibliotecas.

Ele ajuda a:

  • gerenciar dependências;

  • compilar código;

  • executar testes;

  • empacotar aplicações;

  • padronizar a estrutura dos projetos;

  • gerenciar plugins;

  • trabalhar com projetos multimódulo;

  • publicar artefatos.

E talvez a melhor forma de resumir o Maven seja:

Você descreve como seu projeto é organizado e quais são suas necessidades; o Maven automatiza boa parte do trabalho necessário para construir esse projeto.

Se você está seguindo uma trilha de estudos de Java, entender Maven é um daqueles assuntos que parecem simples no começo, mas que vão economizar bastante tempo conforme seus projetos ficam maiores.