Concrete Logo
Hamburger button

Introdução ao Java 9 – Módulos

  • Blog
  • 23 de Outubro de 2017
Share

O objetivo deste post é explicar a parte teórica dos módulos e a seguir vamos fazer uma aplicação simples para ilustrar de forma prática como e onde usá-los. O projeto JigSaw, responsável por incluir a modularização no Java 9, foi iniciado em 2008, com uma fase de exploração, mas já com o objetivo de modularizar o Java. A especificação e implementação foram iniciados em 2014.

O principal objetivo do Jigsaw foi modularizar o jdk e permitir o desenvolvimento de aplicações modulares. Entre as vantagens, estão incluídas isolar as bibliotecas de terceiros, melhorar o encapsulamento e fugir do famoso jarHell.

O jarHell ocorre no momento de compilar a aplicação (cada uma com uma versão), quando temos várias dependências. Já o classpath utiliza a primeira dependência encontrada, eliminando aquelas de outras versões, implicando em erros no momento da execução.

Outra vantagem é que o rt.jar, que existe nas versões anteriores do Java, mas que agora está dividido em módulos, permite que a aplicação utilize apenas os que realmente necessita.

Mas na prática, como vai ser útil para os desenvolvedores? Quais vantagens teremos ao desenvolver nossas aplicações modularizadas? E as desvantagens?

Então, bora lá… Para começar: o que são módulos?

Um módulo é um grupo de componentes (objetos, classes, pacotes, jars) que agrupam um contexto do sistema.

E para que servem?

Servem, basicamente, para que possamos deixar explícito em nossa aplicação quais são os recursos que queremos utilizar e, de fato, quando nossa aplicação sobe, sabendo que a jvm importa a aloca na memória só o que definimos, com isso o app vai consumir menos recursos da máquina. Resumindo, podemos limitar o import de uma biblioteca de terceiros apenas ao módulo que necessita diretamente dessa biblioteca, tornando-a exclusiva para o módulo.

Como se define/cria um módulo?

Para criar um módulo precisamos pensar na arquitetura da aplicação… se aquele pacote ou conjunto de pacotes suprem uma necessidade específica da aplicação.

Por exemplo: faz sentido isolar o pacote com.app.data em uma aplicação comum, no qual a data contém toda a lógica de acesso ao dado.

Por convenção, adicionamos o pacote do exemplo com.app.data dentro de um diretório de mesmo nome, e no diretório criado adicionamos o arquivo module-info.java.

A estrutura de um módulo é bem simples:

Contém a palavra module seguido do nome do módulo com.app.data. Desta forma, o jdk vai passar a enxergar o pacote como um módulo. Para configurar e definir como ele vai interagir com a aplicação, precisamos das diretivas do módulo conforme vamos ver a seguir.

Existem apenas cinco diretivas para compor a configuração de um módulo. Cada diretiva tem uma função e seu uso é simples. São elas: requires, exports, opens, provides e uses.

Requires: funciona como um import. Ele que declara no módulo “client” a utilização de outro módulo.

Ex.:

Exports: exporta os objetos públicos do módulo, tornando-os acessíveis para outros módulos.

Ex.:

Opens: tem função semelhante ao export, com a diferença que se expõe não somente a objetos públicos, por isso torna todos os objetos acessíveis para outros módulos.

Ex.:

Provides: utilizado em conjunto com o with, configura a interface disponibilizada e escolhe qual a implementação que vai ser injetada.

Ex.:

Uses: explicita a utilização da interface disponibilizada com o provides no módulo “client”.

Ex.:

Além das diretivas, existem modificadores auxiliares, como o to, static, transitive e with.

to: designa a configuração para um módulo específico.

static: utilizado em conjunto com o requires, torna obrigatória a existência apenas em tempo de compilação, sendo opcional em execução. Se o módulo alvo do requires static se utilizar de outros módulos, ele se torna também obrigatório em execução.

Ex.:

transitive: utilizado em conjunto com o requires, faz com que o módulo exportado fique visível implicitamente também aos consumidores do módulo.

Ex.:

with: (explicado acima) é obrigatório na declaração do provides.

Ex.:

Podemos contar ainda com o auxílio do compilador e/ou IDE, que informa eventuais problemas de configuração dos módulos, auxiliando o desenvolvedor .

Exemplo de erro:

Package ‘com.app.data’ is declared in module ‘com.app.data’, which does not export it to module ‘com.app.service’. 

A mensagem do compilador é clara, o pacote com.app.data do módulo com.app.data não está sendo exportado para o módulo com.app.service. O que o desenvolvedor precisa fazer é especificar no módulo com.app.data o export para o módulo com.app.service, conforme exemplo abaixo.

As duas opções abaixo são válidas, porém utilizando o modificador to apenas o módulo com.app.service terá acesso ao módulo data.

Por hoje é só. No próximo post, vamos fazer um passo a passo desde o início da série.

É desenvolvedor Java e gostaria de trabalhar em um time ágil e multidisciplinar? Clique aqui!