[Pesquisar este blog]

quarta-feira, 3 de janeiro de 2018

Java 9::Jigsaw, a nova modularidade da plataforma (Parte II)

Depois de mais de oito anos de trabalho, o projeto Jigsaw e o novo sistema de modularidade para a plataforma Java estreiam na versão 9, trazendo um grande conjunto de novas possibilidades para o desenvolvimento de software.
Desenvolvimento modular com Java 9
Desenvolvimento modular com Java 9
A parte I deste post abordou o conceito de modularidade e a especificação do novo artefato module trazida pelo Jigsaw.

Agora, na parte II, será discutida a implementação do Jigsaw na versão 9 do Java. Para finalizar este post, na parte III, temos um exemplo de construção de uma aplicação modular.

O JDK modularizado

Uma das queixas frequentes sobre a plataforma Java era o fato de sua API nativa ser constituída de um monólito de código gigantesco. Estamos falando do famigerado arquivo rt.jar (Java Runtime archive). Qualquer aplicação Java executada na versão 8 (ou anterior), requer que o rt.jar esteja disponível, pois nele residem todas as classes e interfaces padronizadas da máquina virtual. Como tal arquivo é grande, o trabalho da JVM para localizar e extrair qualquer tipo necessário para a aplicação em execução é, obviamente, mais demorado do que a execução destas mesmas tarefas em arquivos menores.

A versão do rt.jar localizada no subdiretório lib do JRE possuia 51,9MB no JRE 1.8.0_121. Já a versão armazenada no subdiretório jre\lib, do JRE incluso no JDK da mesma versão 1.8.1_121, tem 60.4MB. Ambos possuem mais de 19000 arquivos distintos.

Além da mencionada dificuldade no carregamento de tipos, o tamanho do rt.jar é proibitivo em aplicações destinadas a equipamentos que não sejam computadores, por exemplo, para dispositivos "vestíveis" (wearable devices) ou embutidos (embeded devices).

Outro problema, menos discutido, mas igualmente presente, é a inconveniente dependência cíclica, pouco intuitiva, existente entre alguns de seus elementos.

Como já visto, o ponto de partida do projeto Jigsaw foi a criação de um novo artefato module que, conforme a especificação da versão 9, é um arquivo JAR modular. Um arquivo JAR modular é um arquivo JAR que possui um descritor de módulo, module-info.class, no diretório raiz do arquivo JAR. Tal descritor é a forma binária da declaração de um módulo.

Uma das maiores tarefas do projeto Jigsaw foi dividir o arquivo rt.jar em um conjunto adequado de módulos, menores, interdependentes, mas sem dependências circulares. O resultado pode ser visto na figura que segue (que precisa ser ampliada - basta clicar - para que seus detalhes sejam observados).

Hierarquia dos módulos no Java 9

Na parte inferior da figura podemos ver o módulo java.base, o único que não depende de outros - que possui arestas de chegada. Todo e qualquer módulo criado lê (ou depende de) java.base, implícita ou explicitamente, de maneira similar a importação do pacote java.lang.

O módulo java.base exporta pacotes como java.lang, java.util, java.math etc., que são praticamente onipresentes em qualquer aplicação Java.

Os novos módulos são como novos componentes, carregados por meio de um modulepath (que substitui o antigo classpath), mais simples e mais eficiente. Um classpath típico lista os diretórios onde residem os pacotes, sem deixar claro quais são os pacotes necessários dentro de cada um dos diretórios indicados. Já um modulepath lista apenas os módulo necessários, reduzindo a incerteza em relação aos elementos necessários para uma aplicação.

Na versão 9 o JDK é tipicamente instalado num diretório jdk-9, que possui um subdiretório jmods que contém todos os módulos da API Java, resultado do trabalho de modularização do Jigsaw. O modulo java.base está contido no arquivo java.base.jmod que possui apenas 15.8MB. Os arquivos de extensão jmod tem formato compatível ao dos arquivos jar, ou seja, são uma espécie de arquivo compactado no formato ZIP. O tamanho total do subdiretório jmods é 116MB (maior que o antigo rt.jar). Além disso, existe um arquivo modules (sem extensão), no subdiretório lib, com 167MB, que condensa todos os módulos, e cuja existência é garantir a compatibilidade com as aplicações produzidas por versões anteriores ao Java 9.

Já a versão 9 do JRE, instalada num diretório jre-9, existe apenas o subdiretório lib, no qual existe o arquivo modules com 107MB, requerido para executar qualquer aplicação Java. 

A presença do arquivo modules, embora pareça recriar a situação anterior do rt.jar, é uma consequência da retrocompatibilidade garantida pelo Java 9 em relação às versões anteriores. Esta é a configuração default do JDK e do JRE nesta versão. Mas a grande diferença proporcionada pelo Jigsaw está naquilo que pode ser feito além da configuração padrão.

Com a modularização do JDK torna-se possível especificar quais módulos do Java Runtime serão usados, reduzindo o trabalho da JVM na localização de tipos (com menos módulos, menos tipos, menos trabalho no carregamento de classes). Assim, se a aplicação não usa componentes Swing, o módulo java.desktop não precisa ser incluído; se o suporte para Corba não é necessário, nada  de especificar java.corba; e assim por diante. Apenas o módulo java.base é essencial (por isso é carregado implicitamente).

Na prática, isto significa que o Java 9 torna possível customizar a JVM para conter apenas os módulos necessários a um conjunto específico de aplicações; até mesmo otimizando-o para uma única aplicação especial. Quando tal customização não é feita, a configuração default, de compatibilidade mais ampla, é garantida.

jlink

A nova ferramenta de linha de comando jlink permite que sejam escolhidos os módulos e dependências a serem inclusas em uma distribuição, com granularidade muito fina, unindo-os. Isto muito contribui para reduzir e controlar o tamanho das distribuições. 

Abaixo temos o formato típico da linha de comando do jlink, envolvendo o modulepath, os módulos inclusos e a indicação da saída.

> jlink --module-path <modulepath>
       --add-modules <module>[,<module>...]
       --output <path>

Com isto o jlink permite criar um arquivo modules completamente customizado para uma aplicação específica, o que permite otimizar a JVM para ambientes particulares. Dentre as várias opções do jlink é possível indicar o nível de compressão dos módulos, os serviços interligados, plugins, a lista de módulos observados, etc.

Um exemplo de uso do jlink é:

> jlink --module-path %JAVA_HOME%/jmods;projectMod
      --add-modules br.gov.sp.fatec.saudacoes
      --output saudacoesapp

Este comando cria uma imagem runtime que contém o módulo br.gov.sp.fatec.saudacoes, incluindo suas dependências transitivas (isto é, decorrentes de sua execução). O valor de --module-path é o caminho dos diretórios contendo os módulos previamente empacotados. Use ';' como separadores de diretório no Microsoft Windows e ':' no Unix/Linux. Assim, %JAVA_HOME%/jmods é o diretório que contém o módulo java.base.jmod (e os demais módulos padrão do JDK). O diretório projecMod, incluído no modulepath, é aquele que contém os demais artefatos, no caso, o módulo denominado br.gov.sp.fatec.saudacoes. A saída produzida, a imagem da aplicação, será armazenada no diretório saudacoesapp.

Além disso, o jlink permite também controle avançado sobre a ligação entre os módulos, com a possibilidade de escolhe entre ligação estática (static linking), que cria módulos maiores, mas mais rápidos; e ligação dinâmica (dynamic linking), que cria módulos menores, mas com mais tempo de carregamento maior.


Conclusões

O Jigsaw tem um papel central no Java, pois com ele se espera melhorar a modularidade, a eficiência e também a segurança da plataforma. Com ele torna-se possível criar aplicações mais escaláveis, leves, robustas e seguras.

A ambição maior do Jigsaw é incentivar o desenvolvimento de um ecossistema completo baseado na linguagem e na JVM, por meio de um software develpment kit (SDK) modular, para criar aplicações modulares com uso de ferramentas igualmente modulares.

Concretamente o Jigsaw permite solucionar o JAR hell (vide primeira parte do post); obter melhor encapsulamento e segurança entre pacotes e clientes destes pacotes; performance melhorada e tamanho reduzido do ambiente mínimo requerido para aplicações modulares.

Na próxima e última parte deste post será construída uma aplicação modular.

Para Saber Mais



Nenhum comentário: