Boas Práticas para o Arquivo settings.xml
O arquivo de configuração do Maven está localizado em M2_HOME/conf/settings.xml. Modificar diretamente esse arquivo afeta globalmente todos os usuários do sistema operacional. A abordagem recomendada é copiar esse arquivo para ~/.m2/settings.xml, criando uma configuração isolada por usuário, sem interferir entre diferentes contas no mesmo máquina.
Essa estratégia também simplifica atualizações do Maven: ao instalar uma nova versão, não é necessário reconfigurar o arquivo, pois as definições personalizadas permanecem no diretório do usuário.
Verificando a Instalação
Após descompactar o Maven, configurar variáveis de ambiente e ajustar o settings.xml, execute:
mvn help:system
Esse comando utiliza o plugin help para exibir informações do sistema. Caso o plugin não esteja disponível localmente, o Maven fará o download a partir do repositório remoto, validando assim a conectividade e as configurações de repositório. O comando mvn -v apenas confirma a instalação e as variáveis de ambiente, sem validar alterações no settings.xml.
Definindo a Versão do Compilador Java
Por padrão, o Maven pode utilizar uma versão antiga do compilador. É recomendável especificar explicitamente a versão desejada:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<release>11</release>
</configuration>
</plugin>
</plugins>
</build>
Criando Projetos com Archetype
Para gerar a estrutura inicial de um projeto via linha de comando:
mvn archetype:generate
O Maven solicitará a seleção de um arquétipo e, em seguida, os parâmetros groupId, artifactId, version e package.
Gerando um JAR Executável
O JAR produzido pelo ciclo padrão de build não é executável diretamente, pois o manifesto não contém a classe principal. Para resolver isso, utiliza-se o maven-shade-plugin:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.4</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.exemplo.AppPrincipal</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
O JAR resultante poderá ser executado com java -jar arquivo.jar.
Gerenciamento de Dependências
Excluindo Dependências Transitivas
Conflitos de versão podem surgir devido à dependência transitiva. Para excluir uma biblioteca indesejada que vem arrastada por outra:
<dependency>
<groupId>com.exemplo</groupId>
<artifactId>modulo-principal</artifactId>
<version>2.1.0</version>
<exclusions>
<exclusion>
<groupId>com.exemplo</groupId>
<artifactId>modulo-indesejado</artifactId>
</exclusion>
</exclusions>
</dependency>
A tag <exclusions> pode conter múltiplos elementos <exclusion>, sendo necessário apenas groupId e artifactId para identificar unicamente a dependência.
Dependências Opcionais
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.2.18</version>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
O atributo optional indica que essa dependência está disponível apenas para o projeto atual. Projetos downstream que dependam deste não receberão essa biblioteca por transitividade, devendo declará-la explicitamente caso necessário.
Repositórios
Configurando Repositórios Remotos
O repositório local padrão fica em ~/.m2/repository. Para alterar o caminho, modifique o elemento localRepository no settings.xml. Já os repositórios remotos são configurados no POM do projeto:
<repositories>
<repository>
<id>jboss-repo</id>
<name>Repositório JBoss</name>
<url>https://repository.jboss.org/nexus/content/groups/public/</url>
<releases>
<enabled>true</enabled>
<updatePolicy>daily</updatePolicy>
<checksumPolicy>ignore</checksumPolicy>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
<layout>default</layout>
</repository>
</repositories>
updatePolicy controla a frequência de verificação de atualizações: daily (padrão), never, always ou interval:X (a cada X minutos). checksumPolicy define o comportamento ao falhar a verificação de checksum: warn (padrão), fail ou ignore.
Autenticação em Repositórios Remotos
As credenciais de acesso não devem ser armazenadas no POM, pois este é versionado em controle de código. Elas devem ser declaradas no settings.xml:
<servers>
<server>
<id>jboss-repo</id>
<username>usuario</username>
<password>senha</password>
</server>
</servers>
O id deve coincidir com o id do repositório definido no POM, estabelecendo a ligação entre a configuração de repositório e as credenciais.
Herança e Agregação
Agregação reúne múltiplos módulos em um projeto unificado, enquanto herança permite que módulos filhos reaproveitem configurações do pai. Na prática, o POM pai centraliza ambas as funções:
<?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>com.exemplo</groupId>
<artifactId>projeto-pai</artifactId>
<packaging>pom</packaging>
<version>1.0.0-SNAPSHOT</version>
<properties>
<java.version>11</java.version>
</properties>
<modules>
<module>modulo-core</module>
<module>modulo-web</module>
</modules>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.3.0</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
dependencyManagement e pluginManagement apenas declararam versões sem importar de fato as dependências. Os módulos filhos precisam declarar explicitamente as dependências desejadas, herdando apenas a versão gerenciada pelo pai.
Para importar configurações de gerenciamento de um POM externo, utilize o escopo import:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.exemplo</groupId>
<artifactId>bom-configuracoes</artifactId>
<version>2.0.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
No módulo filho, a herança é estabelecida com a tag <parent>:
<parent>
<groupId>com.exemplo</groupId>
<artifactId>projeto-pai</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
Build Seletivo de Módulos
Em projetos grandes, construir todos os módulos é dispendioso. O Maven oferece parâmetros para construir apenas o necessário, respeitando a ordem de dependências (conceito de reator):
-am(also-make): constrói o módulo especificado e suas dependências-amd(also-make-dependents): constrói módulos que dependem do módulo especificado-pl(projects): lista de módulos separados por vírgula-rf(resume-from): retoma o build a partir de um módulo específico
Exemplo: compilar o módulo modulo-web e suas dependências:
mvn clean install -pl modulo-web -am
Super POM
Todos os POMs herdam de um Super POM, que define configurações padrão como estrutura de diretórios (src/main/java, src/test/java), diretório de saída (target) e versões de plugins essenciais. Esse arquivo está dentro de $M2_HOME/lib/maven-model-builder-*.jar em org/apache/maven/model/pom-4.0.0.xml.
Para sobrescrever convenções (não recomendado), modifique o elemento <build>:
<build>
<sourceDirectory>src/codigo</sourceDirectory>
</build>
Testes
Ignorando Testes
Durante o desenvolvimento, pode ser necessário pular testes. Há duas abordagens:
1. Via linha de comando (temporário):
mvn package -DskipTests
Compila os testes, mas não os executa. Para pular também a compilação:
mvn package -Dmaven.test.skip=true
2. Via configuração de plugin (persistente):
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M5</version>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>
Para pular também a compilação dos testes, adicione:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<executions>
<execution>
<id>testCompile</id>
<phase>none</phase>
</execution>
</executions>
</plugin>
Executando Testes Específicos
O parâmetro test permite selecionar testes:
mvn test -Dtest=ClasseDeTeste
Curingas são aceitos: -Dtest=*Integracao*. Para múltiplas classes, use vírgulas. Se nenhum teste corresponder, use -DfailIfNoTests=false para evitar erro:
mvn test -Dtest=*Integracao* -DfailIfNoTests=false
Incluindo e Excluindo Testes
Por padrão, classes terminadas em Test são reconhecidas. Para incluir classes com sufixo Tests:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M5</version>
<configuration>
<includes>
<include>**/*Tests.java</include>
</includes>
</configuration>
</plugin>
Para excluir testes específicos:
<configuration>
<excludes>
<exclude>**/*TesteTemporario.java</exclude>
</excludes>
</configuration>
Empacotando Testes em JAR
Para disponibilizar classes de teste como dependência em outros projetos:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<goals>
<goal>test-jar</goal>
</goals>
</execution>
</executions>
</plugin>
O artefato gerado (artifactId-tests.jar) pode ser declarado como dependência:
<dependency>
<groupId>com.exemplo</groupId>
<artifactId>modulo-core</artifactId>
<version>1.0.0-SNAPSHOT</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
Plugins de Servidor Web
Jetty
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>9.4.44.v20210927</version>
<configuration>
<scanIntervalSeconds>10</scanIntervalSeconds>
<webApp>
<contextPath>/app</contextPath>
</webApp>
</configuration>
</plugin>
scanIntervalSeconds define o intervalo de escaneamento de alterações para hot reload. contextPath define o caminho da aplicação (http://localhost:8080/app/).
Para simplificar a execução, adicione o groupId do plugin no settings.xml:
<settings>
<pluginGroups>
<pluginGroup>org.eclipse.jetty</pluginGroup>
</pluginGroups>
</settings>
Comandos de execução:
mvn jetty:run
mvn jetty:run -Djetty.port=9090
Tomcat
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<port>8080</port>
</configuration>
</plugin>
Execução:
mvn tomcat7:run
Como o plugin não recebe atualizações há bastante tempo, recomenda-se deploy diretamente no contêiner Tomcat.
Propriedades do Maven
O Maven possui seis categorias de propriedades que funcionam como variáveis:
- Internas:
${basedir}(diretório raiz do projeto) e${version}(versão do projeto) - POM: referenciam elementos do POM, como
${project.groupId},${project.artifactId},${project.build.sourceDirectory},${project.build.finalName} - Customizadas: definidas em
<properties>: ``` <versao.spring>5.3.0</versao.spring>Usadas como `${versao.spring}` - Settings: referenciam
settings.xml, como${settings.localRepository} - Sistema Java: propriedades da JVM, como
${user.home}. Liste todas commvn help:system - Variáveis de ambiente: prefixadas com
env., como${env.JAVA_HOME}
Em projetos multi-módulo, essas propriedades reduzem redundância:
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>modulo-dao</artifactId>
<version>${project.version}</version>
</dependency>