Deployment Java / JVM JAR PostgreSQL
Blueprint de Distribuição

Distribuição de Aplicações Java: do JAR ao Instalador

Uma aplicação Java não termina no código — termina no momento em que o cliente a consegue instalar e executar sem assistência. Este artigo cobre a cadeia completa: o modelo de compilação da JVM, a fronteira de responsabilidades entre developer e cliente, a gestão de dependências externas como o PostgreSQL, e a produção de artefactos de distribuição para Linux e Windows.

Java vs. C: O Modelo de Compilação

Em C, o compilador produz código máquina nativo — instruções binárias específicas para uma CPU e sistema operativo. Um binário compilado para x86_64 Linux não corre em ARM Windows. Para múltiplas plataformas, é preciso compilar uma vez por alvo.

Java introduz uma camada intermédia: o compilador (javac) produz bytecode — instruções agnósticas à arquitetura, executadas pela JVM que as traduz para a CPU local em tempo de execução.

Modelo C
Compilação Nativa

gcc app.c -o app → binário x86_64.
Para ARM: recompilar. Para Windows: recompilar.
Vantagem: performance máxima, sem runtime.
Desvantagem: um build por plataforma-alvo.

Modelo Java
Bytecode + JVM

javac App.java.class (bytecode).
Um único JAR corre em qualquer plataforma com JVM.
Vantagem: "compile once, run anywhere".
Desvantagem: a JVM tem de estar instalada no destino.

// Cadeia de compilação Java

// 1. Código fonte (.java) → bytecode (.class)
javac src/Main.java
// → target/Main.class  (instruções para a JVM, não para a CPU)

// 2. Empacotamento — todos os .class + dependências → fat JAR
mvn package
// → target/autoflow-1.0.0.jar

// 3. Execução — a JVM JIT-compila o bytecode para a CPU local
java -jar autoflow-1.0.0.jar
// → funciona em x86_64 Linux, ARM macOS, x86_64 Windows
// → desde que exista uma JVM compatível instalada
Fat JAR vs. JAR simples Um JAR simples contém apenas o bytecode do teu projeto — as dependências têm de estar no classpath separadamente. Um fat JAR (produzido por mvn package com Spring Boot) empacota tudo num único ficheiro autocontido. É o artefacto de distribuição standard para aplicações Spring Boot.

A Fronteira de Responsabilidades

Quando uma aplicação depende de software externo — como o PostgreSQL — a questão fundamental é: quem instala o quê? Esta divisão deve ser acordada antes do projeto começar, nunca na entrega.

ResponsabilidadeDeveloperCliente / SysadminNotas
Produzir o JARArtefacto final de distribuição.
Documentar pré-requisitosVersão de Java, PostgreSQL, SO suportados.
Produzir scripts de BD (.sql)Schema, dados iniciais, índices — versionado no repositório.
Produzir scripts de instalação (.sh / .bat)Automatizar o que for possível. Documentar o que não for.
Instalar o Java no servidorOu negociado contratualmente.
Instalar o PostgreSQLDocumentar versão mínima e configuração esperada.
Executar os scripts de BD✅ (com suporte)O developer fornece os scripts; o cliente executa.
Configurar o application.propertiesFornece templatePreenchePasswords e hosts são do ambiente do cliente.
Definir no contrato, não na entrega A fronteira de responsabilidades deve ser acordada antes do projeto começar. Descobrir na entrega que "o cliente não sabia que tinha de instalar o Java" é um problema de gestão, não técnico. O manual de instalação é parte do artefacto entregável — não um extra.

Estrutura de uma Distribuição Profissional

AutoFlow/
├── AutoFlow.jar                    ← artefacto principal (fat JAR)
├── README.txt                      ← manual em texto simples (legível sem browser)
├── README.md                       ← versão Markdown para documentação web
├── config/
│   └── application.properties     ← template de configuração (sem passwords reais)
└── setup/
    ├── schema.sql                  ← script de criação da BD (idempotente)
    ├── setup-bd.sh                 ← instalação para Linux
    └── setup-bd.bat                ← instalação para Windows

Os Scripts de Base de Dados

O script SQL de schema é o artefacto mais crítico da distribuição. Deve ser idempotente (CREATE TABLE IF NOT EXISTS) e versionado no repositório junto ao código.

-- setup/schema.sql — idempotente e auto-documentado
CREATE TABLE IF NOT EXISTS users (
    id            BIGSERIAL    PRIMARY KEY,
    email         VARCHAR(255) NOT NULL UNIQUE,
    password_hash VARCHAR(60)  NOT NULL,
    role          VARCHAR(20)  NOT NULL DEFAULT 'USER',
    created_at    TIMESTAMPTZ  DEFAULT NOW()
);

-- Admin por omissão — password deve ser alterada no primeiro login
INSERT INTO users (email, password_hash, role)
VALUES ('admin@autoflow.local', '$2a$12$...', 'ADMIN')
ON CONFLICT (email) DO NOTHING;
#!/bin/bash
# setup/setup-bd.sh — Linux/macOS
set -e

DB_USER="postgres"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

echo "=== AutoFlow — Configuração da Base de Dados ==="
psql -U "$DB_USER" -f "$SCRIPT_DIR/schema.sql"
echo "✓ Base de dados criada. Configura config/application.properties antes de iniciar."
@echo off
REM setup/setup-bd.bat — Windows
set DB_USER=postgres
set SCRIPT_DIR=%~dp0

echo === AutoFlow — Configuração da Base de Dados ===
psql -U %DB_USER% -f "%SCRIPT_DIR%schema.sql"

if %errorlevel% neq 0 (
    echo ERRO: Falha. Verifica se o PostgreSQL está instalado e a correr.
    pause & exit /b 1
)
echo OK Base de dados criada. Configura config\application.properties antes de iniciar.
pause

O Ficheiro de Configuração

O application.properties distribuído deve ser um template com placeholders documentados — nunca com credenciais reais. As credenciais de produção pertencem ao ambiente do cliente, não ao repositório.

# config/application.properties — TEMPLATE
spring.datasource.url=jdbc:postgresql://localhost:5432/autoflow
spring.datasource.username=postgres
spring.datasource.password=ALTERAR_AQUI                ← obrigatório

server.port=8080

# Gerar com: openssl rand -base64 64
jwt.secret=GERAR_E_COLOCAR_AQUI                        ← obrigatório
jwt.expiration-minutes=15

spring.profiles.active=prod
Nunca versionar credenciais reais O application.properties com passwords nunca deve entrar no repositório Git. Adicionar ao .gitignore. Em produção, usar variáveis de ambiente ou um secrets manager (HashiCorp Vault, AWS Secrets Manager).

Distribuição Avançada: Pacotes Nativos

Para clientes menos técnicos, o instalador nativo elimina os pré-requisitos manuais. Em vez de "instala o Java, executa este JAR", o utilizador recebe um instalador que trata de tudo.

Debian / Ubuntu — Pacote .deb

Um pacote .deb permite instalar com dpkg -i autoflow.deb, declarar dependências (java17, postgresql), criar serviços systemd, e desinstalar limpo com apt remove.

# Estrutura do pacote .deb
autoflow_1.0.0_amd64/
├── DEBIAN/
│   ├── control          ← metadados: nome, versão, dependências
│   ├── postinst         ← script executado após instalação
│   └── prerm            ← script executado antes de desinstalar
└── opt/
    └── autoflow/
        ├── autoflow.jar
        └── config/
            └── application.properties
# DEBIAN/control
Package: autoflow
Version: 1.0.0
Architecture: amd64
Maintainer: RandomT <dev@randomt.pt>
Depends: default-jre-headless (>= 17), postgresql (>= 13)
Description: AutoFlow — Sistema de Gestão

# Construir o pacote
dpkg-deb --build autoflow_1.0.0_amd64
# → autoflow_1.0.0_amd64.deb

# Instalar no cliente — as dependências são verificadas automaticamente
sudo dpkg -i autoflow_1.0.0_amd64.deb
#!/bin/bash
# DEBIAN/postinst — executado automaticamente após instalação
set -e

# Utilizador de sistema dedicado (sem shell de login)
if ! id -u autoflow >/dev/null 2>&1; then
    useradd --system --no-create-home --shell /usr/sbin/nologin autoflow
fi

chown -R autoflow:autoflow /opt/autoflow
systemctl enable autoflow
systemctl start autoflow

echo "AutoFlow instalado. Aceder em: http://localhost:8080"
# /etc/systemd/system/autoflow.service
[Unit]
Description=AutoFlow
After=network.target postgresql.service
Requires=postgresql.service

[Service]
User=autoflow
WorkingDirectory=/opt/autoflow
ExecStart=java -jar /opt/autoflow/autoflow.jar
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

Windows — Instalador com Inno Setup

O Inno Setup produz um .exe de instalação a partir de um script .iss que define ficheiros, atalhos, serviços e verificação de pré-requisitos.

; autoflow.iss — Inno Setup Script
[Setup]
AppName=AutoFlow
AppVersion=1.0.0
DefaultDirName={pf}\AutoFlow
OutputBaseFilename=AutoFlow-Setup-1.0.0

[Files]
Source: "dist\autoflow.jar";  DestDir: "{app}"; Flags: ignoreversion
Source: "dist\config\*";      DestDir: "{app}\config"; Flags: recursesubdirs
Source: "dist\setup\*";       DestDir: "{app}\setup";  Flags: recursesubdirs

[Run]
; Executar o script de BD após instalação
Filename: "{app}\setup\setup-bd.bat";
  Description: "Criar base de dados PostgreSQL";
  Flags: postinstall runascurrentuser

[Code]
// Verificar Java antes de instalar
function InitializeSetup(): Boolean;
begin
  Result := True;
  if Exec('java', '-version', '', SW_HIDE, ewWaitUntilTerminated, ResultCode) then
    Result := True
  else begin
    MsgBox('Java 17 não encontrado. Instala o Java antes de continuar.', mbError, MB_OK);
    Result := False;
  end;
end;

Texto vs. Markdown: Dois Formatos, Dois Públicos

FicheiroFormatoAudiênciaOnde usar
README.txtTexto simples ASCIISysadmin, terminal, cliente técnicoDentro do ZIP de distribuição. Legível sem browser.
README.mdMarkdownDeveloper, documentação webRepositório Git, GitBook, Notion, Academy.
Página HTMLHTML estruturadoEquipa interna, parceirosEste site — manual completo com exemplos de código.

Checklist de Distribuição

Regra de ouro da distribuição Um artefacto bem feito é aquele que permite ao cliente instalar a aplicação sem contactar o developer. Se o cliente precisar de te ligar para completar a instalação, o manual está incompleto.