O que é o Maven?
O Maven é uma ferramenta de gerenciamento de dependências e do ciclo de vida de projetos de software no sentido técnico. Isso inclui:
- Facilitar a compilação do código, o empacotamento (JAR, WAR, EAR, …), a execução de testes unitários, etc.
- Unificar e automatizar o processo de geração do sistema. Nada mais de uma coleção de passos e scripts a serem executados manualmente.
- Centralizar informações organizadas do projeto, incluindo suas dependências, resultados de testes, documentação, etc.
- Reforçar boas práticas de desenvolvimento, tais como: separação de classes de teste das classes do sistema, uso de convenções de nomes e diretórios, etc.
- Ajuda no controle das versões geradas (releases) dos seus projetos.
Conceitos importantes
Artefato (artifact)
Um artefato é geralmente um arquivo JAR que fica no repositório do Maven, mas pode ser de outro tipo.
Cada artefato é identificado através dos seguintes elementos:
- Grupo: é como o endereço do site ao contrário, como
br.com
.starcode
,org.apache
,com.google
,com.ibm
, etc. - Identificador único de artefato: geralmente é o nome do projeto. Ele deve ser único por grupo.
- Número de versão: a versão do projeto, como
1.4.2
ou3.0
. Se houver o sufixo-SNAPSHOT
(0.0.1-SNAPSHOT
, por exemplo) significa que o projeto está em desenvolvimento e o pacote pode ser alterado. - Tipo do projeto: jar, war, ear, pom (projeto de configuração).
- Classificador: identificação opcional para diferenciar variações da mesma versão. Por exemplo, se o programa é compilado para diferentes versões do Java podemos usar os classificadores
jdk4
ejdk6
. Se há variações específicas para Sistemas Operacionais, podemos ter os classificadoreslinux
ewindows
.
Repositório local
É um diretório em seu PC onde os artefatos são armazenados após baixados de um repositório remoto na internet ou na intranet. Você também pode instalar os artefatos dos seus projetos nesse repositório executando oinstall
do Maven. Continue lendo para entender o que é isso.
O repositório possui uma estrutura padrão onde o Maven consegue encontrar os artefatos através da identificação do mesmo.
Repositório remoto
Consiste numa aplicação que disponibiliza artefatos do Maven. Pode se um repositório público na Internet, onde criadores de bibliotecas e frameworks disponibilizam seus artefatos, ou pode ser um repositório privado da empresa, disponível na intranet.
Existe um repositório central que já vem configurando no Maven, mas algumas empresas criam seus próprios repositórios. Inclusive você pode criar o seu instalando oArtifactoryouNexusnum servidor.
Quando adicionamos esses repositórios remotos em nossa instalação do Maven, ele é capaz de localizar e baixar automaticamente as dependências através da identificação do artefato.
Arquivo POM
O arquivo pom (pom.xml
) é a configuração principal do Maven e estará presente em todo projeto. Nele você declara a identificação do seu projeto (que após gerado será também um artefato Maven), as dependências, repositórios adicionais, etc.
Há um arquivo pom por projeto, mas ele pode herdar configurações de umparent pom, isto é, como se houvesse um projeto “pai”.
Ciclo de vida padrão do Maven
O Maven possui um ciclo de vida padrão. Cada passo do ciclo de vida é chamado de_Goal_e possui plugins específicos. Os mais importantes são:
validate
: valida o projeto e se as informações necessárias para os próximos passos estão disponíveis, como as dependências por exemplo.compile
: compila o código-fonte.test
: executa os testes unitários (JUnit, por exemplo).package
: empacota o código compilado em um JAR, WAR, etc.integration-test
: executa os testes de integração.install
: adiciona o pacote gerado ao repositório local, assim outros projetos na mesma máquina podem usar essa dependência.deploy
: copia o pacote final para o repositório remoto, disponibilizando-o para outros desenvolvedores e outros projetos.
Os itens acima, nessa ordem, são passos comuns para geração de uma versão de qualquer sistema, não é mesmo?
No Maven, você pode configurar detalhadamente cada um desses passos e até incluir novos. Por exemplo, alguns frameworks que geram código-fonte usam umgoalgenerate-sources
para fazer isso.
Além disso, não é necessário executar todos os passos sempre. Você pode escolher qual deseja executar num determinado momento, mas o Maven sempre executará todos os passos anteriores.
Por exemplo, enquanto você está desenvolvendo um módulo, a cada alteração pode executar o passotest
para executar a validação, compilação e então os testes unitários. Então você só precisa executar os passos posteriores quando tiver concluído o trabalho.
Para maiores informações sobre o ciclo de vida, consulte a documentação.
Estrutura padrão de um projeto Maven
A estrutura padrão do projeto inclui boas práticas (como separar as classes de teste das classes do sistema) e facilita aos novos desenvolvedores encontrar o que eles querem, já que todos os projetos seguirão uma estrutura semelhante.
Veja a seguir os principais diretórios utilizados:
src/main/java
: aqui fica o código-fonte do sistema ou biblioteca.src/main/resources
: arquivos auxiliares do sistema, como.properties
, XMLs e configurações.src/main/webapp
: se for uma aplicação web, os arquivos JSP, HTML, JavaScript CSS vão aqui, incuindo oweb.xml
.src/test/java
: as classes com seus testes unitários ficam aqui e são executadas automaticamente com JUnit e TestNG. Outros frameworks podem exigir configuração adicional.src/test/resources
: arquivos auxiliares usados nos testes. Você pode ter properties e configurações alternativas.pom.xml
: é o arquivo que concentra as informações do seu projeto.target
: é o diretório onde fica tudo que é gerado, isto é, onde vão parar os arquivos compilados, JARs, WARs, JavaDoc, etc.
Para ver mais detalhes sobre a estrutura de diretórios do Maven, consulte a documentação.
Benefícios do Maven
A adoção do Maven no desenvolvimento traz de imediato os seguintes benefícios:
Centralização das informações
O Maven centraliza as informações dos projetos no arquivo pom.
Sendo assim, não é preciso configurar várias ferramentas, build scripts, servidores e IDEs durante o desenvolvimento. O Maven segue o conceito DRY(Don’t Repeat Yourself).
Além disso, o Maven também disponibiliza formas de analisar o projeto. Por exemplo, o goal dependency:analyze
exibe as dependências declaradas que não estão sendo usadas e as usadas via terceiros, mas não declaradas no pom.
Padronização do ambiente de desenvolvimento
Através da especificação do projeto, incluindo suas características e dependências, o Maven constrói a estrutura necessária do projeto, baixando automaticamente as versões corretas das dependências (JARs, por exemplo) de um repositório central ou de um repositório privado (contendo sistemas da empresa).
Você não precisa entrar no site de cada biblioteca e framework usado e então fazer manualmente o download e adicionar os jars no seu classpath.
Dessa forma, cada desenvolvedor consegue configurar rapidamente um ambiente para desenvolvimento com a garantia de que esse ambiente é igual ao dos outros desenvolvedores.
Gerenciamento de dependências
Como já mencionei, o Maven faz o download automático de dependências para o projeto e os adiciona ao _classpath_do seu projeto.
Cada dependência pode ter também as suas próprias dependências. Elas são chamadas dependências transitivas. O Maven resolve essa árvore de dependências e traz tudo o que você precisa.
Em alguns casos, podem haver problemas de conflitos, no caso da árvore de dependências incluir versões diferentes de um mesmo artefato. O Maven vem com mecanismos para resolver isso.
Facilidade de compreensão do projeto
Ao usar a convenção de diretórios sugerida pelo Maven os desenvolvedores terão mais facilidade em compreender a estrutura do projeto, afinal todos os projetos seguirão uma estrutura básica de diretórios, como vimos anteriormente.
Automação
O Maven gerencia o ciclo de vida da aplicação. Após configurar um projeto, você será capaz de executar comandos que vão desde a compilação até a geração de documentação (Javadoc) e um site padrão contendo informações sobre o projeto.
Uma vez feita a configuração necessária, o projeto pode ser baixado e compilado sem nenhum esforço. Novas versões podem ser geradas em servidores de Integração Contínua e testadas automaticamente sempre que necessário.
Um alerta
Embora os tópicos anteriores tenham enumerado diversas vantagens do uso do Maven, este não é uma “bala de prata”, ou seja, uma solução mágica para o projeto.
Dependendo da complexidade do projeto, pode ser bem complicado criar uma configuração adequada para ao Maven.
Além disso, o Maven não irá livrá-lo de problemas como:
Incompatibilidade de dependências
O projeto depende dos frameworks A e B. O framework A depende a versão 1.0 da biblioteca C. O framework B depende da versão 2.0 da biblioteca C.
O Maven não vai resolver sozinho isso, mas facilita muito a resolução do problema já que podemos usar as informações do mecanismo de resolução de dependências para identificar os conflitos.
Algumas tecnologias simplesmente não vão funcionar bem com o Maven
Alguns autores de frameworks ou arquiteturas inventam o seu próprio jeito de trabalhar. Isso significa que para usar o Maven é necessário alguma adaptação, o que nem sempre é trivial.
No entanto, é possível escrever plugins para o Maven que façam o trabalho para você. Geralmente a comunidade de cada framework, se não os próprios autores, já terão resolvido esse problema. Embora existam casos em que essas soluções acrescentem novas limitações.
Usando o Maven
Criando um projeto Maven simples no Eclipse
Com o Maven configurado, vamos criar um novo projeto no Eclipse.
- Acesse o menu
File > New > Maven Project
. - Selecione a opção
Create a simple project (skip archetype selection)
- clique clique em
Next >
.
Vamos preencher a identificação do projeto, que nada mais é do que a identificação de um artefato.
OGroup Id
para o exemplo serábr.com
.starcode
e oArtifact Id
seráteste-maven-01
. A versão e o tipo de artefato (Packaging) já devem estar preenchidos, então simplesmente deixe como está. O nome e a descrição são opcionais.
Clique emFinish
para ver o projeto criado.
Note que ele ainda não está definido com as configurações de um projeto Java, então clique com o botão direito sobre o projeto, acesse o menuMaven > Update Project...
.
Clique emOK
para atualizar o projeto com as configurações do Maven e agora temos a estrutura característica.
Executando os passos (goals) do Maven
Vamos supor que estamos construindo uma nova biblioteca. Precisaremos testá-la(test),empacotá-la(package) num jar e distribuí-la(deploy) para o uso de terceiros, não é mesmo? O Maven nos ajuda grandemente com esses passos naturais do ciclo de vida de um projeto.
Vamos ainda criar um teste unitário para nossa classe, as primeiro temos que adicionar a dependência do JUnit ao nosso projeto. Para isso vá até o site mvnrepository.come pesquise porjunit
. Vá até a última versão, copie o trecho do XML e adicione na seção de dependências do seupom.xml
.
Adicione também a tag<scope>test</scope>
à esta dependência, para informar ao Maven que ela somente será usada no teste. Sim, o Maven é “esperto” e não incluirá, por exemplo, o JUnit na pastaWEB-INF/lib
de uma aplicação web.
Ao salvar o arquivo o Maven deve baixar o JUnit automaticamente.
Caso queira executar o teste já, clique com o botão direito sobre a classe e acesse o menuRun As > JUnit Test
Iniciando o projeto
- No eclipse clique em
File > New > Project
- Selecione
Maven Project
e clique em Next - Selecione
Create a simple project (skipe archetype selection)
e clique em Next - Complete os campos com os dados necessários e clique em Finish
Para compilar o código-fonte do nosso projeto, o comando utilizado é mvn compile
. As classes serão geradas no diretório target/classes
.
Para rodar os testes, utilizamos mvn test
. No terminal, o comando nos mostra o resultado da execução de cada um dos arquivos de teste, bem como um resumo geral: quantos testes foram executados, quantos falharam, etc.
Além disso, o mvn test
gera dois diretórios dentro de target
: o test-classes
, que contém os arquivos class
dos arquivos de teste, e o surefire-reports
onde podemos ver arquivos com o resultado da execução dos testes nos arquivos de teste.
Para limpar o diretório target
, utilizamos o comando mvn clean
.
Para gerar o arquivo jar
do nosso projeto executamos:
mvn package
validate
- : valida se todas as informações necessárias estão disponíveis
compile
: compila o código-fontetest
: executa os testes de unidade
<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/maven-v4_0_0.xsd">
<!-- informações sobre o projeto -->
<dependencies>
<!-- dependências do junit e xstream -->
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pmd-plugin</artifactId>
<version>3.6</version>
<executions>
<execution>
<phase>verify</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
<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/maven-v4_0_0.xsd">
<!-- informacoes -->
<dependencies>
<!-- depedências -->
</dependencies>
<build>
<plugins>
<!-- PMD plugin -->
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.7.6.201602180812</version>
<executions>
<execution>
<goals>
<goal>prepare-agent</goal>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Em projetos com muitas dependências, com o passar do tempo elas podem ficar desatualizadas, caso você queira atualizar as dependências para suas versões mais atuais, poderá utilizar o seguinte comando: mvn versions:use-latest-versions
Existe um outro goals que verifica por atualizações sem de fato alterar o pom.xml: mvn versions:display-dependency-updates
O escopo compile indica que a dependência estará disponível em todos os classpaths: de compilação de teste e execução. Esse é o escopo padrão utilizado quando não declaramos um escopo na dependência.
O escopo provided indica que precisamos da dependência para compilar e testar, mas não se faz necessário incluir a dependência no artefato final, pois o JDK ou o container irão disponibilizar a dependência.
O escopo de runtime indica que não necessitamos da dependência para compilar. A dependência estará disponível no classpath de runtime, o que significa que utilizaremos a dependência na execução do projeto. A dependência também estará disponível no classpath de testes.
Para excluir uma dependência que foi incluída em algum projeto que utilizamos, basta utilizar a tag exclusion:
<dependency>
<groupId>br.com.alura.maven</groupId>
<artifactId>produtos</artifactId>
<version>1.0-SNAPSHOT</version>
<exclusions>
<exclusion>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
</exclusion>
</exclusions>
</dependency>