Construindo aplicativos Java com Bazel

Construindo aplicativos Java com Bazel

1. Visão geral

Bazel é uma ferramenta de código-fonte aberto para construir e testar o código-fonte, semelhante ao Maven e Gradle. It supports projects in multiple languages and builds outputs for multiple platforms.

Neste tutorial, seguiremos as etapas necessárias para construir um aplicativo Java simples usando o Bazel. Para ilustração, começaremos com um projeto Maven multimódulo e, em seguida, construiremos o código-fonte usando o Bazel.

Começaremos porinstalling Bazel.

2. Estrutura do Projeto

Vamos criar um projeto Maven de vários módulos:

bazel (root)
    pom.xml
    WORKSPACE (bazel workspace)
    |— bazelapp
        pom.xml
        BUILD (bazel build file)
        |— src
            |— main
                |— java
            |— test
                |— java
    |— bazelgreeting
        pom.xml
        BUILD (bazel build file)
        |— src
            |— main
                |— java
            |— test
                |— java

A presença deWORKSPACE file sets up the workspace for Bazel. Pode haver um ou vários deles em um projeto. Para nosso exemplo, manteremos apenas um arquivo no diretório do projeto de nível superior.

O próximo arquivo importante é oBUILD file, which contains the build rules. Ele identifica cada regra com umtargetname exclusivo.

Bazel oferece flexibilidade parahave as many BUILD files as we need, configurado para qualquer nível de granularidade. Isso significaria que podemos construir um número menor de classes Java configurando regrasBUILD adequadamente. Para manter as coisas simples, manteremos o mínimo de arquivosBUILD em nosso exemplo.

Como a saída da configuração do BazelBUILD é normalmente um arquivo jar, iremos referir cada diretório que contém o arquivoBUILD como um pacote de compilação.

3. Criar arquivo

3.1. Configuração de regra

É hora de configurar nossa primeira regra de construção para construir os binários Java. Vamos configurar um no arquivoBUILD pertencente ao módulobazelapp:

java_binary (
    name = "BazelApp",
    srcs = glob(["src/main/java/com/example/*.java"]),
    main_class = "com.example.BazelApp"
)

Vamos entender as definições de configuração uma por uma:

  • java_binary - o nome da regra; requer atributos adicionais para construir os binários

  • name - o nome do destino de construção

  • srcs - uma matriz dos padrões de localização de arquivo que informam quais arquivos Java construir

  • main_class - o nome da classe principal do aplicativo (opcional) [selectionBoundary_1566278670065_7250327636179006 .rangySelectionBoundary] #

3.2. Execução de construção

Agora somos bons para criar o aplicativo. A partir do diretório que contém o arquivoWORKSPACE,, vamos executar o comandobazel build em um shell para construir nosso destino:

$ bazel build //bazelapp:BazelApp

O último argumento é o nome do destino configurado em um dos arquivosBUILD. Possui o padrão “//<path_to_build>:<target_name>“.

A primeira parte do padrão, “//”, indica que estamos começando em nosso diretório de espaço de trabalho. O próximo,“bazelapp”, é o caminho relativo para o arquivoBUILD do diretório da área de trabalho. Finalmente,“BazelApp” é o nome do destino a ser construído.

3.3. Criar saída

Agora devemos observar dois arquivos de saída binários da etapa anterior:

bazel-bin/bazelapp/BazelApp.jar
bazel-bin/bazelapp/BazelApp

OBazelApp.jar contém todas as classes, enquantoBazelApp é um script wrapper para executar o arquivo jar.

3.4. JAR implantável

Talvez seja necessário enviar o jar e suas dependências para diferentes locais para implantação.

O script wrapper da seção acima especifica todas as dependências (arquivos jar) como parte do comando de inicialização deBazelApp.jar.

No entanto, também podemos fazer um frasco de gordura contendo todas as dependências:

$ bazel build //bazelapp:BazelApp_deploy.jar

Sufixar o nome do destino com“_deploy”instructs Bazel to package all the dependencies within the jar e torná-lo pronto para implantação.

4. Dependências

Até agora, só construímos usando os arquivos embazelapp.. Mas, quase todos os aplicativos têm dependências.

Nesta seção, veremos como empacotar as dependências junto com o arquivo jar.

4.1. Construindo Bibliotecas

Antes de fazermos isso, porém, precisamos de uma dependência quebazelapp possa usar.

Vamos criar outro módulo Maven chamadobazelgreeting e configurar o arquivoBUILD para o novo módulo com a regrajava_library. Chamaremos esse destino de “greeter”:

java_library (
    name = "greeter",
    srcs = glob(["src/main/java/com/example/*.java"])
)

Aqui, usamos a regrajava_library para criar a biblioteca. Depois de construir esse destino, obteremos o arquivolibgreetings.jar:

INFO: Found 1 target...
Target //bazelgreeting:greetings up-to-date:
  bazel-bin/bazelgreeting/libgreetings.jar

4.2. Configurando Dependências

Para usargreeter embazelapp, precisaremos de algumas configurações adicionais. Primeiro, precisamos tornar o pacote visível parabazelapp. Podemos conseguir isso adicionando o atributovisibility na regrajava_library do pacotegreeter:

java_library (
    name = "greeter",
    srcs = glob(["src/main/java/com/example/*.java"]),
    visibility = ["//bazelapp:__pkg__"]
)

O atributovisibility torna o pacote atual visível para aqueles listados na matriz.

Agora no pacotebazelapp, devemos configurar a dependência do pacotegreeter. Vamos fazer isso com o atributodeps:

java_binary (
    name = "BazelApp",
    srcs = glob(["src/main/java/com/example/*.java"]),
    main_class = "com.example.BazelApp",
    deps = ["//bazelgreeting:greeter"]
)

O atributodeps torna o pacote atual dependente daqueles listados na matriz.

5. Dependências externas

Podemos trabalhar em projetos que possuem vários espaços de trabalho e dependem um do outro. Ou podemos importar bibliotecas de locais remotos. Podemos categorizar essas dependências externas como:#[#selectionBoundary_1566279863846_1839671609791924 .rangySelectionBoundary] #

  • Local Dependencies: nós os gerenciamos dentro do mesmo espaço de trabalho que vimos na seção anterior ou abrangemos vários espaços de trabalho

  • HTTP Archives: Nós importamos as bibliotecas de um local remoto via HTTP

Existem muitas regras do Bazel disponíveis para gerenciarexternal dependencies. Veremos como importar arquivos jar do local remoto nas seções subsequentes.

5.1. Locais de URL HTTP

Para nosso exemplo, vamos importarApache Commons Lang para nosso aplicativo. Como temos que importar este jar do local HTTP, usaremos a regrahttp_jar. Vamos primeiro carregar a regra das definições de compilação HTTP do Bazel e configurá-la no arquivoWORKSPACE com a localização do Apache Commons:

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_jar")

http_jar (
    name = "apache-commons-lang",
    url = "https://repo1.maven.org/maven2/org/apache/commons/commons-lang3/3.9/commons-lang3-3.9.jar"
)

Devemos ainda adicionar dependências no arquivoBUILD do pacote “bazelapp”:

deps = ["//bazelgreeting:greeter", "@apache-commons-lang//jar"]

Observe que precisamos especificar o mesmo nome usado na regrahttp_jar do arquivoWORKSPACE.

5.2. Dependências do Maven

Gerenciar arquivos jar individuais se torna uma tarefa tediosa. Alternativamente, podemosconfigure the Maven repository using the rules_jvm_external rule em nosso arquivoWORKSPACE. Isso nos permitirá buscar quantas dependências queremos em nosso projeto nos repositórios.

Primeiro, devemos importar a regrarules_jvm_external de um local remoto usando a regrahttp_archive no arquivoWORKSPACE:

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")

RULES_JVM_EXTERNAL_TAG = "2.0.1"
RULES_JVM_EXTERNAL_SHA = "55e8d3951647ae3dffde22b4f7f8dee11b3f70f3f89424713debd7076197eaca"

http_archive(
    name = "rules_jvm_external",
    strip_prefix = "rules_jvm_external-%s" % RULES_JVM_EXTERNAL_TAG,
    sha256 = RULES_JVM_EXTERNAL_SHA,
    url = "https://github.com/bazelbuild/rules_jvm_external/archive/%s.zip" % RULES_JVM_EXTERNAL_TAG,
)

A seguir, usaremos a regramaven_install e configuraremos a URL do repositório Maven e os artefatos necessários:

load("@rules_jvm_external//:defs.bzl", "maven_install")

maven_install(
    artifacts = [
        "org.apache.commons:commons-lang3:3.9" ],
    repositories = [ 
        "https://repo1.maven.org/maven2",
    ] )

Por fim, adicionaremos a dependência no arquivoBUILD:

deps = ["//bazelgreeting:greeter", "@maven//:org_apache_commons_commons_lang3"]

Ele resolve os nomes dos artefatos usando caracteres de sublinhado (_).

6. Conclusão

Neste tutorial, aprendemos configurações básicas para criar um projeto Java no estilo Maven com a ferramenta de construção Bazel.

O código-fonte também está disponível emGitHub. Ele existe como um projeto Maven e também é configurado com os arquivos BazelWORKSPACEeBUILD.