<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Cesar Schutz</title><description>Cesar Schutz, arquiteto de soluções. Artigos sobre arquitetura de software, engenharia de software, Java e IA — o que eu estudo, revisado por mim e com código testado.</description><link>https://cesarschutz.com.br/</link><language>pt-BR</language><item><title>Java 29 (próxima LTS) — o que o Java 26 e o 27 já trouxeram</title><link>https://cesarschutz.com.br/posts/java-29/</link><guid isPermaLink="true">https://cesarschutz.com.br/posts/java-29/</guid><description>O caminho do Java 25 até a próxima LTS, o Java 29 (prevista para setembro de 2027): as JEPs do Java 26 e do 27, o que ainda está em preview, exemplos de código e o que conferir na migração.</description><pubDate>Wed, 16 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Última atualização:&lt;/strong&gt; 16/09/2026. Cobre o Java 26 (lançado em 17/03/2026) e o Java 27 (lançado em 15/09/2026). O Java 28 ainda está em desenvolvimento, e o conteúdo do Java 29 ainda não foi definido.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;A série “Atualizações do Java” acompanha só as versões LTS. Entre uma LTS e outra saem versões intermediárias a cada seis meses, e cada uma pode trazer recursos novos, promover um preview a final ou remover algo antigo. Este post junta o que já saiu desde o Java 25 e diz &lt;strong&gt;em qual versão cada coisa chegou&lt;/strong&gt; e em qual status ela está hoje. Ele será atualizado quando o Java 28 e o Java 29 saírem.&lt;/p&gt;
&lt;p&gt;O Java 26 chegou à disponibilidade geral (GA, a versão final para produção) em 17 de março de 2026 (&lt;a href=&quot;https://openjdk.org/projects/jdk/26/&quot;&gt;JDK 26&lt;/a&gt;), e o Java 27, em 15 de setembro de 2026 (&lt;a href=&quot;https://openjdk.org/projects/jdk/27/&quot;&gt;JDK 27&lt;/a&gt;). A próxima LTS prevista é o &lt;strong&gt;Java 29, em setembro de 2027&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Essa previsão vem do &lt;a href=&quot;https://www.oracle.com/java/technologies/java-se-support-roadmap.html&quot;&gt;Oracle Java SE Support Roadmap&lt;/a&gt; (atualizado em 15/09/2026). Ele classifica o 26, o 27 e o 28 como não LTS e avisa que essa classificação e as datas ainda podem mudar. Nesse roadmap, cada versão não LTS tem Premier Support só até a seguinte sair: setembro de 2026 para o 26 e março de 2027 para o 27. Para o Java 25, a Oracle informa Premier Support até setembro de 2030; para o Java 29, prevê até setembro de 2032. Outros fornecedores de builds do OpenJDK publicam seus próprios prazos. Na data desta atualização, o OpenJDK ainda não tinha publicado a página do projeto JDK 29.&lt;/p&gt;
&lt;p&gt;O post é para quem está no &lt;strong&gt;Java 25&lt;/strong&gt; e quer acompanhar o que muda até o 29. O ponto de partida é o &lt;a href=&quot;https://cesarschutz.com.br/posts/java-25/&quot;&gt;post do Java 25&lt;/a&gt;; quem vem do Java 21 deve ler os dois. Para a visão geral de ciclo de releases, distribuições e estratégia de migração, veja o &lt;a href=&quot;https://cesarschutz.com.br/posts/guia-atualizacoes-java/&quot;&gt;guia de atualizações do Java&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Como o post está organizado.&lt;/strong&gt; Primeiro, uma linha do tempo com todas as trilhas. Depois, os recursos que já são definitivos, agrupados por tema: concorrência, APIs, JVM, ferramentas, segurança e remoções. Em seguida vêm os recursos que continuam em preview ou incubadora, uma lista do que pode quebrar na migração vindo do Java 25 e, por fim, a tabela de todas as JEPs de cada versão, incluindo o que já tem alvo no Java 28. Cada recurso traz a linha &lt;strong&gt;Chegou em&lt;/strong&gt;, com a versão e a JEP (a proposta formal de mudança do OpenJDK) em que ele apareceu.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Preview e incubadora não são definitivos.&lt;/strong&gt; Pela &lt;a href=&quot;https://openjdk.org/jeps/12&quot;&gt;JEP 12&lt;/a&gt;, um recurso em &lt;strong&gt;preview&lt;/strong&gt; está completo, mas não é permanente: numa versão futura ele pode virar final, com ou sem ajustes, ou ser removido. Para usá-lo é preciso &lt;code&gt;--enable-preview&lt;/code&gt; na compilação e na execução, e uma JVM não carrega classes compiladas com os previews de outra versão. Já as APIs em &lt;strong&gt;incubadora&lt;/strong&gt; (&lt;a href=&quot;https://openjdk.org/jeps/11&quot;&gt;JEP 11&lt;/a&gt;) ficam em módulos &lt;code&gt;jdk.incubator.*&lt;/code&gt;, precisam de &lt;code&gt;--add-modules&lt;/code&gt; e podem mudar ou sumir com a mesma liberdade. Os exemplos de preview abaixo refletem o Java 27 e podem precisar de ajuste no Java 28 ou no 29.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Os exemplos que só dependem do Java 26 foram compilados e executados no Temurin 26.0.2. Os que usam recursos exclusivos do 27 (&lt;code&gt;Set.ofLazy&lt;/code&gt;, o &lt;code&gt;StructuredTaskScope&lt;/code&gt; do 27, o mascaramento de dados do JFR e &lt;code&gt;-XX:AOTMode=required&lt;/code&gt;) seguem as assinaturas do código-fonte do JDK 27 (tag &lt;code&gt;jdk-27-ga&lt;/code&gt;) e as notas de release.&lt;/p&gt;
&lt;h2 id=&quot;linha-do-tempo&quot;&gt;Linha do tempo&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#linha-do-tempo&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://cesarschutz.com.br/posts/java-29/linha-do-tempo.svg&quot; alt=&quot;Linha do tempo do Java 25 ao Java 29: trilhas de Lazy Constants, Structured Concurrency, primitivos em patterns, API PEM e Vector API passando por previews e incubadoras; compact object headers e G1 virando padrão no Java 27; outras JEPs de cada versão e o que já é alvo do Java 28&quot;&gt;&lt;/p&gt;
&lt;p&gt;O diagrama mostra cada trilha versão a versão. A linha vermelha marca a data desta atualização: à direita dela, tudo é previsão.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Java 26&lt;/strong&gt; (&lt;a href=&quot;https://openjdk.org/projects/jdk/26/&quot;&gt;página do projeto&lt;/a&gt;), 10 JEPs: HTTP/3 no &lt;code&gt;HttpClient&lt;/code&gt;, cache AOT com qualquer coletor, G1 com menos sincronização, avisos para quem altera campos &lt;code&gt;final&lt;/code&gt; por reflexão e a remoção da Applet API.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Java 27&lt;/strong&gt; (&lt;a href=&quot;https://openjdk.org/projects/jdk/27/&quot;&gt;página do projeto&lt;/a&gt;), 9 JEPs: G1 como padrão em qualquer ambiente, compact object headers por padrão, TLS 1.3 com troca de chaves pós-quântica e mascaramento de dados sensíveis nas gravações do JFR.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Java 28&lt;/strong&gt; (&lt;a href=&quot;https://openjdk.org/projects/jdk/28/&quot;&gt;página do projeto&lt;/a&gt;), 6 JEPs com alvo até agora, entre elas a API PEM final e o primeiro preview de Value Objects (&lt;a href=&quot;#java-28&quot;&gt;detalhes&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Os recursos em preview e incubadora (Structured Concurrency, primitivos em patterns, Lazy Constants, API PEM e Vector API) estão reunidos em &lt;a href=&quot;#ainda-em-preview-ou-incubadora&quot;&gt;Ainda em preview ou incubadora&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;concorrência&quot;&gt;Concorrência&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#concorrência&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;virtual-threads-liberam-a-carrier-enquanto-esperam-a-inicialização-de-uma-classe&quot;&gt;Virtual threads liberam a carrier enquanto esperam a inicialização de uma classe&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#virtual-threads-liberam-a-carrier-enquanto-esperam-a-inicialização-de-uma-classe&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Chegou em:&lt;/strong&gt; Java 26 (final, &lt;a href=&quot;https://bugs.openjdk.org/browse/JDK-8369238&quot;&gt;JDK-8369238&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;Uma virtual thread não tem thread do sistema operacional própria: ela é executada em cima de uma &lt;strong&gt;carrier thread&lt;/strong&gt;, uma thread de plataforma de um pool compartilhado pela JVM. Quando a virtual thread bloqueia, a JVM a “desmonta” da carrier, que fica livre para executar outra virtual thread. Se ela não pode ser desmontada, fica &lt;strong&gt;presa (pinned)&lt;/strong&gt; e ocupa a carrier durante toda a espera. O Java 24 resolveu esse problema para &lt;code&gt;synchronized&lt;/code&gt; (veja &lt;a href=&quot;https://cesarschutz.com.br/posts/java-25/#synchronized-n%C3%A3o-prende-mais-virtual-threads&quot;&gt;&lt;code&gt;synchronized&lt;/code&gt; não prende mais virtual threads&lt;/a&gt;, no post do Java 25), mas ainda havia outros casos.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;O problema.&lt;/strong&gt; Até o Java 25, uma virtual thread que precisava de uma classe que outra thread ainda estava inicializando (rodando o bloco &lt;code&gt;static&lt;/code&gt;, por exemplo) ficava presa à carrier enquanto esperava. No pior caso, todas as carriers ficavam presas nessa espera enquanto o inicializador dependia de uma virtual thread para terminar, e a aplicação inteira travava.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;O que mudou.&lt;/strong&gt; Segundo as &lt;a href=&quot;https://www.oracle.com/java/technologies/javase/26-relnote-issues.html&quot;&gt;notas de release do Java 26&lt;/a&gt;, na maioria dos casos a virtual thread agora é desmontada durante essa espera e libera a carrier. A mudança não é uma JEP e não exige nenhuma alteração no código: basta rodar no Java 26 ou posterior.&lt;/p&gt;
&lt;h2 id=&quot;apis-da-biblioteca-padrão&quot;&gt;APIs da biblioteca padrão&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#apis-da-biblioteca-padrão&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;http3-no-httpclient&quot;&gt;HTTP/3 no HttpClient&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#http3-no-httpclient&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Chegou em:&lt;/strong&gt; Java 26 (final, &lt;a href=&quot;https://openjdk.org/jeps/517&quot;&gt;JEP 517&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;O problema.&lt;/strong&gt; O &lt;code&gt;java.net.http.HttpClient&lt;/code&gt; (&lt;a href=&quot;https://openjdk.org/jeps/321&quot;&gt;JEP 321&lt;/a&gt;, Java 11, &lt;a href=&quot;https://cesarschutz.com.br/posts/java-11/#http-client&quot;&gt;HTTP Client no post do Java 11&lt;/a&gt;) falava HTTP/1.1 e HTTP/2. O HTTP/3, padronizado pela IETF em 2022, troca o TCP pelo QUIC, um protocolo de transporte que roda sobre UDP. A JEP cita as vantagens: handshakes (a negociação inicial da conexão) potencialmente mais rápidos, menos problemas de congestionamento, como o head-of-line blocking (quando um pacote perdido atrasa todas as requisições da conexão), e transporte mais confiável em redes que perdem muitos pacotes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;O que mudou.&lt;/strong&gt; O HTTP/3 é &lt;strong&gt;opt-in&lt;/strong&gt;: o padrão continua sendo HTTP/2. Você escolhe &lt;code&gt;HttpClient.Version.HTTP_3&lt;/code&gt; no cliente ou em cada requisição. Por padrão, se o servidor não fala HTTP/3, o cliente volta para HTTP/2 ou HTTP/1.1 sem erro (a exceção é o modo &lt;code&gt;HTTP_3_URI_ONLY&lt;/code&gt;, na tabela abaixo). Como não dá para saber de antemão se o servidor fala HTTP/3, a JEP descreve quatro estratégias de descoberta:&lt;/p&gt;
&lt;div class=&quot;table-wrap&quot;&gt;
























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Configuração&lt;/th&gt;&lt;th&gt;Comportamento&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;HTTP_3&lt;/code&gt; como versão preferida da requisição&lt;/td&gt;&lt;td&gt;Tenta HTTP/3 primeiro e cai para HTTP/2 ou HTTP/1.1 se a conexão não abrir em tempo razoável.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;HTTP_3&lt;/code&gt; só no cliente, sem versão na requisição&lt;/td&gt;&lt;td&gt;Tenta HTTP/3 e HTTP/2 ou HTTP/1.1 em paralelo e usa a conexão que abrir primeiro.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;HttpOption.H3_DISCOVERY&lt;/code&gt; com &lt;code&gt;Http3DiscoveryMode.ALT_SVC&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Começa em HTTP/2 ou HTTP/1.1 e passa a usar HTTP/3 nas requisições seguintes se o servidor anunciar o serviço alternativo.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;HttpOption.H3_DISCOVERY&lt;/code&gt; com &lt;code&gt;Http3DiscoveryMode.HTTP_3_URI_ONLY&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Usa só HTTP/3 e falha se o servidor não responder por ele.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;As duas últimas estratégias usam a opção de requisição &lt;code&gt;H3_DISCOVERY&lt;/code&gt; e exigem &lt;code&gt;HTTP_3&lt;/code&gt; como versão preferida no cliente ou na requisição.&lt;/p&gt;
&lt;p&gt;O exemplo abaixo usa a terceira estratégia (&lt;code&gt;ALT_SVC&lt;/code&gt;). Ele acessa um servidor externo, &lt;code&gt;www.google.com&lt;/code&gt;, e só chega ao HTTP/3 porque esse servidor anuncia suporte no cabeçalho &lt;code&gt;Alt-Svc&lt;/code&gt; da resposta. Com um servidor que não anuncia HTTP/3, as duas chamadas saem em &lt;code&gt;HTTP_2&lt;/code&gt;; sem acesso à internet, &lt;code&gt;send&lt;/code&gt; lança exceção.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://cesarschutz.com.br/_astro/ec.bzl1c.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://cesarschutz.com.br/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;ClienteHttp3.java&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; java.net.URI;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; java.net.http.HttpClient;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; java.net.http.HttpOption;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; java.net.http.HttpOption.Http3DiscoveryMode;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; java.net.http.HttpRequest;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; java.net.http.HttpResponse.BodyHandlers;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;ClienteHttp3&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;main&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;[] &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;args&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;throws&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; Exception {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// Preferência por HTTP/3 em todas as requisições deste cliente&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;HttpClient client &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; HttpClient.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;newBuilder&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;version&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(HttpClient.Version.HTTP_3)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;build&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// Servidor externo: o resultado depende de ele anunciar HTTP/3 (Alt-Svc)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;HttpRequest request &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; HttpRequest.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;newBuilder&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(URI.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;create&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;https://www.google.com/&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;setOption&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(HttpOption.H3_DISCOVERY, Http3DiscoveryMode.ALT_SVC)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;GET&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;build&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// 1ª chamada: sai por HTTP/2 e lê o Alt-Svc da resposta&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; primeira &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; client.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;send&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(request, BodyHandlers.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;discarding&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;());&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;IO.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(primeira.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;version&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;());   &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// HTTP_2&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// 2ª chamada: já usa HTTP/3, se o servidor anunciou&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; segunda &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; client.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;send&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(request, BodyHandlers.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;discarding&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;());&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;IO.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(segunda.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;version&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;());    &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// HTTP_3&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;No Temurin 26.0.2, com acesso à internet em 16/09/2026, esse programa imprimiu &lt;code&gt;HTTP_2&lt;/code&gt; e depois &lt;code&gt;HTTP_3&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Quando usar e cuidados.&lt;/strong&gt; Vale testar o HTTP/3 com servidores e CDNs que já o oferecem, principalmente em redes com perda de pacotes. Limitações da primeira versão, segundo a JEP: só funciona com o provider TLS padrão (SunJSSE), não há API pública de QUIC nem servidor HTTP/3, e o &lt;code&gt;java.net.URL&lt;/code&gt; continua só em HTTP/1.1.&lt;/p&gt;
&lt;h3 id=&quot;apis-menores-sem-jep&quot;&gt;APIs menores sem JEP&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#apis-menores-sem-jep&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Nem toda mudança de API passa por uma JEP. As notas de release registram várias adições pequenas e úteis.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Java 26&lt;/strong&gt; (&lt;a href=&quot;https://www.oracle.com/java/technologies/javase/26-relnote-issues.html&quot;&gt;notas de release&lt;/a&gt;):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Process&lt;/code&gt; implementa &lt;code&gt;AutoCloseable&lt;/code&gt; (e &lt;code&gt;Closeable&lt;/code&gt;): fechar o processo garante que ele terminou e libera streams e recursos, então dá para usá-lo em &lt;code&gt;try&lt;/code&gt;-with-resources.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Comparator&lt;/code&gt; ganhou os métodos default &lt;code&gt;min(T, T)&lt;/code&gt; e &lt;code&gt;max(T, T)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;UUID.ofEpochMillis(long)&lt;/code&gt; cria UUIDs versão 7, que começam pelo timestamp, em milissegundos, e por isso ficam ordenados pelo instante de criação.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Instant.plusSaturating(Duration)&lt;/code&gt; soma sem estourar: no limite, devolve &lt;code&gt;Instant.MIN&lt;/code&gt; ou &lt;code&gt;Instant.MAX&lt;/code&gt;. &lt;code&gt;Duration&lt;/code&gt; ganhou as constantes &lt;code&gt;MIN&lt;/code&gt; e &lt;code&gt;MAX&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;HttpRequest.BodyPublishers.ofFileChannel(channel, offset, length)&lt;/code&gt; envia só um trecho de um arquivo, útil para upload em partes.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;java.nio.ByteOrder&lt;/code&gt; virou &lt;code&gt;enum&lt;/code&gt; e pode ser usado em &lt;code&gt;switch&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Suporte a Unicode 17.0 e ao JDBC 4.5 MR, que inclui os tipos SQL &lt;code&gt;DECFLOAT&lt;/code&gt; e &lt;code&gt;JSON&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;ApisMenores.java&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; java.time.Duration;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; java.time.Instant;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; java.util.Comparator;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; java.util.UUID;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;ApisMenores&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;main&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;[] &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;args&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;throws&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; Exception {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// Process agora é AutoCloseable: processo e streams são liberados ao sair do bloco&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// (a saída de &quot;java -version&quot; vai para o stream do processo, não aparece aqui)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;try&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (Process p &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;ProcessBuilder&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;java&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;-version&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;start&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;()) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;p.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;waitFor&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// Comparator ganhou min/max entre dois valores&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;Comparator&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&gt; porTamanho &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; Comparator.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;comparingInt&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(String&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;length);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;IO.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(porTamanho.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;max&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;java&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;kotlin&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;));   &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// kotlin&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// UUID versão 7, ordenável pelo instante de criação&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;UUID id &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; UUID.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;ofEpochMillis&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(System.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;currentTimeMillis&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;());&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;IO.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(id.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;version&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;());                        &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// 7&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// Soma saturada: em vez de estourar, para no limite&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;IO.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(Instant.MAX.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;minusSeconds&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;plusSaturating&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(Duration.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;ofDays&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;equals&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(Instant.MAX));                   &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// true&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;IO.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(Duration.MAX);                        &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// PT2562047788015215H30M7.999999999S&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Java 27&lt;/strong&gt; (&lt;a href=&quot;https://jdk.java.net/27/release-notes&quot;&gt;notas de release&lt;/a&gt;): &lt;code&gt;KeyStore.getCreationInstant&lt;/code&gt; devolve a data de criação de uma entrada como &lt;code&gt;Instant&lt;/code&gt;; na Foreign Function &amp;#x26; Memory API, &lt;code&gt;Linker.Option.captureCallState&lt;/code&gt; também inicializa o estado thread-local antes da downcall (a chamada de Java para uma função nativa); e os formatadores ISO predefinidos de &lt;code&gt;DateTimeFormatter&lt;/code&gt; passam a aceitar offsets curtos, como &lt;code&gt;+01&lt;/code&gt;, no parsing.&lt;/p&gt;
&lt;h2 id=&quot;jvm-gc-e-desempenho&quot;&gt;JVM, GC e desempenho&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#jvm-gc-e-desempenho&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;g1-com-menos-sincronização-entre-aplicação-e-gc&quot;&gt;G1 com menos sincronização entre aplicação e GC&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#g1-com-menos-sincronização-entre-aplicação-e-gc&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Chegou em:&lt;/strong&gt; Java 26 (final, &lt;a href=&quot;https://openjdk.org/jeps/522&quot;&gt;JEP 522&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;O G1 divide o heap em regiões e, para não varrer o heap inteiro a cada coleta, anota numa &lt;strong&gt;card table&lt;/strong&gt; quais trechos da memória guardam referências para objetos de outras regiões. Quem mantém essa tabela são as &lt;strong&gt;write barriers&lt;/strong&gt;: pequenos trechos de código que a JVM injeta na aplicação e que rodam a cada atribuição de referência, como &lt;code&gt;pedido.cliente = c&lt;/code&gt;. Em segundo plano, threads de otimização do G1 processam a mesma tabela.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;O problema.&lt;/strong&gt; Até o Java 25, a aplicação e as threads de otimização mexiam na mesma card table e precisavam se sincronizar. Essa sincronização deixava as write barriers longas e lentas, e elas rodam o tempo todo.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;O que mudou.&lt;/strong&gt; A JEP 522 cria uma &lt;strong&gt;segunda card table&lt;/strong&gt;. A aplicação escreve numa tabela sem sincronizar, as threads de otimização trabalham na outra, e o G1 troca as duas de forma atômica quando precisa.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cesarschutz.com.br/posts/java-29/g1-duas-card-tables.svg&quot; alt=&quot;Comparação entre o G1 até o Java 25, com aplicação e threads de otimização disputando uma única card table sincronizada, e o G1 do Java 26, com duas card tables: a aplicação escreve numa, as threads de otimização processam a outra e o G1 troca as duas de forma atômica&quot;&gt;&lt;/p&gt;
&lt;p&gt;No diagrama, à esquerda está o modelo antigo, com uma tabela disputada pelos dois lados; à direita, o novo, em que cada lado tem a sua tabela e as setas laranja indicam a troca.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Resultado e custo.&lt;/strong&gt; A JEP relata ganhos de throughput (trabalho feito por unidade de tempo) de 5% a 15% em aplicações que modificam muitos campos de referência, e de até 5% nas demais. No x64, as write barriers caíram de cerca de 50 instruções para 12. O custo é memória nativa: cada card table ocupa 0,2% da capacidade do heap, ou cerca de 2 MB por GB. Não há flag nova: basta usar o G1 no Java 26 ou posterior.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cesarschutz.com.br/posts/java-29/jvm-padroes-java-27.svg&quot; alt=&quot;Dois padrões da JVM que mudam no Java 27: sem flag explícita, o coletor passa a ser sempre G1 (antes era Serial em máquinas com 1 CPU ou menos de 1792 MB), e o cabeçalho de objeto passa de 96 para 64 bits&quot;&gt;&lt;/p&gt;
&lt;p&gt;O Java 27 muda dois padrões da JVM, resumidos no diagrama e detalhados nas duas seções seguintes: o coletor escolhido quando nenhum é informado e o tamanho do cabeçalho dos objetos. Os dois só afetam quem não passa a flag correspondente na linha de comando.&lt;/p&gt;
&lt;h3 id=&quot;g1-como-coletor-padrão-em-qualquer-ambiente&quot;&gt;G1 como coletor padrão em qualquer ambiente&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#g1-como-coletor-padrão-em-qualquer-ambiente&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Chegou em:&lt;/strong&gt; Java 27 (final, &lt;a href=&quot;https://openjdk.org/jeps/523&quot;&gt;JEP 523&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;O problema.&lt;/strong&gt; Desde o Java 9 (&lt;a href=&quot;https://openjdk.org/jeps/248&quot;&gt;JEP 248&lt;/a&gt;, veja &lt;a href=&quot;https://cesarschutz.com.br/posts/java-11/#g1-como-coletor-padr%C3%A3o&quot;&gt;G1 como coletor padrão no post do Java 11&lt;/a&gt;), o G1 era o padrão apenas em máquinas “server”. Com 1 CPU ou menos de 1792 MB de memória física, a JVM escolhia o Serial, um coletor mais simples, que usa uma única thread. Assim, a mesma aplicação podia rodar com coletores diferentes conforme a máquina.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;O que mudou.&lt;/strong&gt; A JEP 523 afirma que o G1 ficou competitivo com o Serial em qualquer tamanho de heap, em parte graças à JEP 522. Por isso, sem um coletor na linha de comando, a JVM agora escolhe &lt;strong&gt;sempre o G1&lt;/strong&gt;. O Serial continua disponível com &lt;code&gt;-XX:+UseSerialGC&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cuidados.&lt;/strong&gt; Na prática, isso atinge principalmente containers com limites baixos, porque a JVM considera os limites do container ao contar CPUs e memória (veja &lt;a href=&quot;https://cesarschutz.com.br/posts/java-11/#jvm-ciente-de-cont%C3%AAineres&quot;&gt;JVM ciente de contêineres no post do Java 11&lt;/a&gt;). Se o limite é 1 CPU ou menos de 1792 MB e ninguém escolheu o coletor, o Java 27 passa a rodar G1. As flags &lt;code&gt;AlwaysActAsServerClassMachine&lt;/code&gt; e &lt;code&gt;NeverActAsServerClassMachine&lt;/code&gt;, que influenciavam essa escolha, foram depreciadas no Java 26 (&lt;a href=&quot;https://www.oracle.com/java/technologies/javase/26-relnote-issues.html&quot;&gt;notas de release do 26&lt;/a&gt;).&lt;/p&gt;
&lt;h3 id=&quot;compact-object-headers-ligados-por-padrão&quot;&gt;Compact object headers ligados por padrão&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#compact-object-headers-ligados-por-padrão&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Chegou em:&lt;/strong&gt; Java 24 (experimental, &lt;a href=&quot;https://openjdk.org/jeps/450&quot;&gt;JEP 450&lt;/a&gt;) → Java 25 (final, &lt;a href=&quot;https://openjdk.org/jeps/519&quot;&gt;JEP 519&lt;/a&gt;) → Java 27 (final, &lt;a href=&quot;https://openjdk.org/jeps/534&quot;&gt;JEP 534&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;Cada objeto Java carrega um cabeçalho com dados que a JVM usa internamente, como o hash, a idade do objeto para o GC e um ponteiro para a classe. Em arquiteturas de 64 bits, esse cabeçalho ocupava 96 bits; com compact object headers, ocupa 64. Como a maioria dos objetos é pequena (a &lt;a href=&quot;https://openjdk.org/jeps/450&quot;&gt;JEP 450&lt;/a&gt; cita tamanhos médios de 32 a 64 bytes), o cabeçalho sozinho podia ocupar mais de 20% dos dados vivos, e os 32 bits economizados em cada objeto fazem diferença.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;O que mudou.&lt;/strong&gt; No Java 25 o recurso já era de produto, mas era preciso pedir com &lt;code&gt;-XX:+UseCompactObjectHeaders&lt;/code&gt; (veja &lt;a href=&quot;https://cesarschutz.com.br/posts/java-25/#compact-object-headers&quot;&gt;Compact object headers no post do Java 25&lt;/a&gt;). No 27, esse é o layout padrão. A JEP 534 cita os experimentos que motivaram a mudança, entre eles um cenário em que o SPECjbb2015 usou 22% menos heap e 8% menos CPU, o uso em centenas de serviços em produção na Amazon e a adoção como padrão no SapMachine, a distribuição da SAP.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cuidados.&lt;/strong&gt; Para voltar ao layout antigo, use &lt;code&gt;-XX:-UseCompactObjectHeaders&lt;/code&gt;. As &lt;a href=&quot;https://jdk.java.net/27/release-notes&quot;&gt;notas do Java 27&lt;/a&gt; avisam que essa flag deve ser depreciada e removida no futuro. O JDK traz arquivos CDS (Class Data Sharing, com metadados de classes já processados para acelerar o startup) separados para cada modo, então desligar o recurso não faz perder esse ganho.&lt;/p&gt;
&lt;h3 id=&quot;cache-aot-com-qualquer-coletor-inclusive-zgc&quot;&gt;Cache AOT com qualquer coletor, inclusive ZGC&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#cache-aot-com-qualquer-coletor-inclusive-zgc&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Chegou em:&lt;/strong&gt; Java 26 (final, &lt;a href=&quot;https://openjdk.org/jeps/516&quot;&gt;JEP 516&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;O cache AOT (ahead-of-time, “antes da execução”) do Project Leyden (&lt;a href=&quot;https://openjdk.org/jeps/483&quot;&gt;JEP 483&lt;/a&gt;, Java 24, e &lt;a href=&quot;https://openjdk.org/jeps/514&quot;&gt;JEP 514&lt;/a&gt;, Java 25) melhora startup e warmup. Numa &lt;strong&gt;execução de treino&lt;/strong&gt;, a JVM observa a aplicação e grava num arquivo as classes já carregadas e ligadas, além de objetos Java prontos. Nas execuções seguintes, ela reaproveita esse arquivo em vez de refazer o trabalho. O funcionamento está no &lt;a href=&quot;https://cesarschutz.com.br/posts/java-25/#cache-aot-inicializa%C3%A7%C3%A3o-e-warmup-mais-r%C3%A1pidos-projeto-leyden&quot;&gt;post do Java 25&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;O problema.&lt;/strong&gt; Até o Java 25, os objetos Java do cache ficavam num formato ligado ao layout de memória dos coletores Serial, Parallel e G1, incompatível com o ZGC. Era preciso escolher entre a latência baixa do ZGC e o startup rápido do cache.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;O que mudou.&lt;/strong&gt; A JEP 516 cria um formato &lt;strong&gt;independente de GC&lt;/strong&gt;, chamado streamable: as referências entre objetos viram índices lógicos, e uma thread em segundo plano recria os objetos no heap enquanto a aplicação sobe. O formato antigo, mapeável, continua existindo: nele, os objetos são mapeados direto na memória do heap. A JVM escolhe o formato na hora de gravar o cache. Se o treino usou ZGC, &lt;code&gt;-XX:-UseCompressedOops&lt;/code&gt; ou heap acima de 32 GB, grava no formato streamable; com compressed oops ligado e heap de até 32 GB, grava no formato mapeável. O formato streamable pode ser forçado com &lt;code&gt;-XX:+AOTStreamableObjects&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;aot-com-zgc.sh&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;# Treino e criação do cache em um passo (fluxo da JEP 514, Java 25)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;java&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;-XX:+UseZGC&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;-XX:AOTCacheOutput=app.aot&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;-jar&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;app.jar&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;# Produção usando o cache, agora também com ZGC (Java 26+)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;java&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;-XX:+UseZGC&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;-XX:AOTCache=app.aot&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;-jar&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;app.jar&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Por padrão, se o cache não puder ser usado, a JVM emite um aviso e segue sem ele. Com &lt;code&gt;-XX:AOTMode=on&lt;/code&gt;, ela aborta a inicialização, o que é útil para garantir em produção que o cache está sendo aproveitado (&lt;a href=&quot;https://openjdk.org/jeps/483&quot;&gt;JEP 483&lt;/a&gt;). No Java 27, &lt;code&gt;-XX:AOTMode=required&lt;/code&gt; passou a ser um alias de &lt;code&gt;on&lt;/code&gt; e é a forma recomendada, porque &lt;code&gt;on&lt;/code&gt; deve ser depreciado e removido (&lt;a href=&quot;https://jdk.java.net/27/release-notes&quot;&gt;notas do 27&lt;/a&gt;). O Java 26 não conhece o valor &lt;code&gt;required&lt;/code&gt;: a JVM não inicia com essa flag.&lt;/p&gt;
&lt;h3 id=&quot;outros-ajustes-de-gc-e-runtime&quot;&gt;Outros ajustes de GC e runtime&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#outros-ajustes-de-gc-e-runtime&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;table-wrap&quot;&gt;







































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Mudança&lt;/th&gt;&lt;th&gt;Versão&lt;/th&gt;&lt;th&gt;Fonte&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;G1 passa a lançar &lt;code&gt;OutOfMemoryError&lt;/code&gt; quando o overhead de GC fica excessivo (&lt;code&gt;UseGCOverheadLimit&lt;/code&gt;), como o Parallel já fazia&lt;/td&gt;&lt;td&gt;26&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://www.oracle.com/java/technologies/javase/26-relnote-issues.html&quot;&gt;Notas do 26&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;G1 recupera antes objetos humongous que contêm referências, sem esperar a marcação concorrente&lt;/td&gt;&lt;td&gt;26&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://www.oracle.com/java/technologies/javase/26-relnote-issues.html&quot;&gt;Notas do 26&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Sem &lt;code&gt;-Xms&lt;/code&gt;, o heap inicial passa a ser o mínimo possível (&lt;code&gt;MinHeapSize&lt;/code&gt;), e não mais 1/64 da memória física&lt;/td&gt;&lt;td&gt;26&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://www.oracle.com/java/technologies/javase/26-relnote-issues.html&quot;&gt;Notas do 26&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Padrões de &lt;code&gt;-XX:MinHeapFreeRatio&lt;/code&gt;/&lt;code&gt;MaxHeapFreeRatio&lt;/code&gt; no G1 mudam de 40/70 para 0/100, o que na prática desliga esse redimensionamento do heap&lt;/td&gt;&lt;td&gt;27&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://jdk.java.net/27/release-notes&quot;&gt;Notas do 27&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-XX:InitiatingHeapOccupancyPercent&lt;/code&gt; vira &lt;code&gt;-XX:G1IHOP&lt;/code&gt; (o nome antigo fica como alias depreciado)&lt;/td&gt;&lt;td&gt;27&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://jdk.java.net/27/release-notes&quot;&gt;Notas do 27&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;UseCompressedClassPointers&lt;/code&gt; fica obsoleta: os ponteiros de classe são sempre comprimidos&lt;/td&gt;&lt;td&gt;27&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://jdk.java.net/27/release-notes&quot;&gt;Notas do 27&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;
&lt;h2 id=&quot;ferramentas&quot;&gt;Ferramentas&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#ferramentas&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;jfr-mascara-dados-sensíveis-antes-de-gravar&quot;&gt;JFR mascara dados sensíveis antes de gravar&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#jfr-mascara-dados-sensíveis-antes-de-gravar&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Chegou em:&lt;/strong&gt; Java 27 (final, &lt;a href=&quot;https://openjdk.org/jeps/536&quot;&gt;JEP 536&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;O problema.&lt;/strong&gt; O JDK Flight Recorder (JFR) é o gravador de eventos de diagnóstico embutido na JVM. Toda gravação guarda os argumentos da linha de comando, as variáveis de ambiente e as system properties iniciais. É útil para diagnóstico, mas senhas passadas por &lt;code&gt;-D&lt;/code&gt;, tokens em variáveis de ambiente e argumentos como &lt;code&gt;--dbpassword&lt;/code&gt; iam parar, sem nenhuma proteção, no arquivo &lt;code&gt;.jfr&lt;/code&gt; que depois é compartilhado ou anexado a um chamado.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;O que mudou.&lt;/strong&gt; A partir do Java 27, o JFR &lt;strong&gt;mascara por padrão&lt;/strong&gt;, ainda dentro do processo e antes de escrever o arquivo, os valores que batem com uma lista de filtros. Para chaves, a lista inclui padrões como &lt;code&gt;*password*&lt;/code&gt;, &lt;code&gt;*secret*&lt;/code&gt;, &lt;code&gt;*token*&lt;/code&gt;, &lt;code&gt;*auth*&lt;/code&gt; e &lt;code&gt;*api*key*&lt;/code&gt;. Para argumentos, cobre formas como &lt;code&gt;-*password *&lt;/code&gt;, que pega a opção e o valor seguinte. O valor mascarado aparece como &lt;code&gt;[REDACTED]&lt;/code&gt;. Dá para acrescentar filtros próprios, carregá-los de arquivo ou desligar os padrões:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;jfr-mascaramento.sh&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;# Padrão no Java 27: segredos óbvios já saem como [REDACTED]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;java&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;-XX:StartFlightRecording:filename=dump.jfr&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;-jar&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;app.jar&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;# Acrescentar filtros próprios aos padrões (note o &quot;+&quot;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;java&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;-XX:FlightRecorderOptions:&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&apos;redact-key=+confidencial,redact-argument=+--pin *&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;     &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;-XX:StartFlightRecording:filename=dump.jfr&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;-jar&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;app.jar&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;# Filtros em arquivo e log de depuração do que foi mascarado&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;java&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&apos;-XX:FlightRecorderOptions:redact-argument=@args.txt,redact-key=@keys.txt&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;     &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;-Xlog:jfr+redact=debug&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;-XX:StartFlightRecording:filename=dump.jfr&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;-jar&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;app.jar&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;# Conferir o resultado&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;jfr&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;print&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;--events&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;InitialSystemProperty,JVMInformation,InitialEnvironmentVariable&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;dump.jfr&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;# Desligar os filtros padrão (só se houver motivo)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;java&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;-XX:FlightRecorderOptions:redact-key=none,redact-argument=none&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;-jar&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;app.jar&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Cuidados.&lt;/strong&gt; Sem o &lt;code&gt;+&lt;/code&gt;, os filtros informados substituem a lista padrão em vez de complementá-la (&lt;a href=&quot;https://openjdk.org/jeps/536&quot;&gt;JEP 536&lt;/a&gt;; o &lt;code&gt;+&lt;/code&gt; e o &lt;code&gt;none&lt;/code&gt; também aparecem nas &lt;a href=&quot;https://jdk.java.net/27/release-notes&quot;&gt;notas do Java 27&lt;/a&gt;). Os filtros padrão reconhecem nomes comuns, como &lt;code&gt;password&lt;/code&gt; e &lt;code&gt;token&lt;/code&gt;; um segredo com nome próprio da aplicação só é mascarado se você acrescentar um filtro para ele. No mesmo release, o evento &lt;code&gt;jdk.SystemProcess&lt;/code&gt; deixou de registrar os argumentos de linha de comando de outros processos da máquina.&lt;/p&gt;
&lt;h3 id=&quot;diagnóstico-e-ferramentas-menores&quot;&gt;Diagnóstico e ferramentas menores&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#diagnóstico-e-ferramentas-menores&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Java 26:&lt;/strong&gt; javadoc com tema escuro; o thread dump de &lt;code&gt;jcmd &amp;#x3C;pid&gt; Thread.dump_to_file&lt;/code&gt; mostra o dono do lock de threads estacionadas (&lt;a href=&quot;https://www.oracle.com/java/technologies/javase/26-relnote-issues.html&quot;&gt;notas do 26&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Java 27:&lt;/strong&gt; novo &lt;code&gt;jcmd &amp;#x3C;pid&gt; VM.security_properties&lt;/code&gt;, script de autocompletar do &lt;code&gt;jcmd&lt;/code&gt; para Bash, &lt;code&gt;-XX:FlightRecorderOptions:help&lt;/code&gt; e contagem de file descriptors abertos em &lt;code&gt;VM.info&lt;/code&gt; e no &lt;code&gt;hs_err_pid&lt;/code&gt; (&lt;a href=&quot;https://jdk.java.net/27/release-notes&quot;&gt;notas do 27&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;segurança&quot;&gt;Segurança&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#segurança&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;troca-de-chaves-híbrida-pós-quântica-no-tls-13&quot;&gt;Troca de chaves híbrida pós-quântica no TLS 1.3&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#troca-de-chaves-híbrida-pós-quântica-no-tls-13&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Chegou em:&lt;/strong&gt; Java 27 (final, &lt;a href=&quot;https://openjdk.org/jeps/527&quot;&gt;JEP 527&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;Este recurso usa o ML-KEM, algoritmo resistente a computação quântica que entrou no Java 24 (veja &lt;a href=&quot;https://cesarschutz.com.br/posts/java-25/#criptografia-resistente-a-computa%C3%A7%C3%A3o-qu%C3%A2ntica-ml-kem-e-ml-dsa&quot;&gt;ML-KEM e ML-DSA no post do Java 25&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;O problema.&lt;/strong&gt; Um atacante pode gravar tráfego cifrado hoje e decifrá-lo quando existirem computadores quânticos capazes de quebrar RSA e ECDH. É o ataque conhecido como “harvest now, decrypt later”. A IETF definiu esquemas &lt;strong&gt;híbridos&lt;/strong&gt; para o TLS 1.3, que combinam um algoritmo resistente a ataques quânticos (ML-KEM) com um tradicional (ECDHE). O resultado continua seguro enquanto pelo menos um dos dois resistir.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;O que mudou.&lt;/strong&gt; No TLS, os &lt;strong&gt;named groups&lt;/strong&gt; são os algoritmos de troca de chaves que cliente e servidor negociam no início da conexão (o handshake). O JDK implementa três named groups híbridos: &lt;code&gt;X25519MLKEM768&lt;/code&gt;, &lt;code&gt;SecP256r1MLKEM768&lt;/code&gt; e &lt;code&gt;SecP384r1MLKEM1024&lt;/code&gt;. O &lt;code&gt;X25519MLKEM768&lt;/code&gt; vai para o &lt;strong&gt;topo da lista padrão&lt;/strong&gt;, então quem usa &lt;code&gt;javax.net.ssl&lt;/code&gt; sem escolher grupos passa a oferecê-lo sem mudar código. Os outros dois só são usados se forem configurados. A lista padrão completa fica assim: &lt;code&gt;X25519MLKEM768, x25519, secp256r1, secp384r1, secp521r1, x448, ffdhe2048, ffdhe3072, ffdhe4096&lt;/code&gt;. Para restringir ou reordenar, use a propriedade &lt;code&gt;jdk.tls.namedGroups&lt;/code&gt; ou &lt;code&gt;SSLParameters.setNamedGroups&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;TlsHibrido.java&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; javax.net.ssl.SSLContext;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; javax.net.ssl.SSLParameters;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; javax.net.ssl.SSLSocket;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;TlsHibrido&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;main&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;[] &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;args&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;throws&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; Exception {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;SSLSocket socket &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (SSLSocket) SSLContext.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;getDefault&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;getSocketFactory&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;createSocket&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;SSLParameters params &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; socket.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;getSSLParameters&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// Só é preciso mexer aqui se a política exigir grupos específicos&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;params.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;setNamedGroups&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;[] {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;X25519MLKEM768&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;SecP256r1MLKEM768&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;x25519&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;secp256r1&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;socket.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;setSSLParameters&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(params);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;IO.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(String.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;join&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;, &quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, socket.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;getSSLParameters&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;getNamedGroups&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;()));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// X25519MLKEM768, SecP256r1MLKEM768, x25519, secp256r1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h3 id=&quot;outras-mudanças-de-segurança&quot;&gt;Outras mudanças de segurança&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#outras-mudanças-de-segurança&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;table-wrap&quot;&gt;







































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Mudança&lt;/th&gt;&lt;th&gt;Versão&lt;/th&gt;&lt;th&gt;Fonte&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Novo algoritmo de &lt;code&gt;Cipher&lt;/code&gt; &lt;code&gt;&quot;HPKE&quot;&lt;/code&gt; (Hybrid Public Key Encryption, RFC 9180) com &lt;code&gt;HPKEParameterSpec&lt;/code&gt;&lt;/td&gt;&lt;td&gt;26&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://www.oracle.com/java/technologies/javase/26-relnote-issues.html&quot;&gt;Notas do 26&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Assinatura e verificação de JARs com ML-DSA (&lt;code&gt;jarsigner&lt;/code&gt; e API &lt;code&gt;JarSigner&lt;/code&gt;)&lt;/td&gt;&lt;td&gt;26&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://www.oracle.com/java/technologies/javase/26-relnote-issues.html&quot;&gt;Notas do 26&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Nova propriedade &lt;code&gt;jdk.crypto.disabledAlgorithms&lt;/code&gt; para desabilitar algoritmos na camada JCE&lt;/td&gt;&lt;td&gt;26&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://www.oracle.com/java/technologies/javase/26-relnote-issues.html&quot;&gt;Notas do 26&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Compressão de certificados TLS 1.3 com zlib (RFC 8879), ligada por padrão&lt;/td&gt;&lt;td&gt;27&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://jdk.java.net/27/release-notes&quot;&gt;Notas do 27&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Chaves privadas ML-KEM e ML-DSA passam a ser codificadas em PKCS#8 no formato &lt;code&gt;seed&lt;/code&gt; por padrão&lt;/td&gt;&lt;td&gt;27&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://jdk.java.net/27/release-notes&quot;&gt;Notas do 27&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Otimizações de desempenho em ML-KEM e ML-DSA (SHA-3 em x86_64 com AVX-512) e em X25519/Ed25519 (AArch64 e x86_64)&lt;/td&gt;&lt;td&gt;27&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://jdk.java.net/27/release-notes&quot;&gt;Notas do 27&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;
&lt;h2 id=&quot;removidos-e-depreciados&quot;&gt;Removidos e depreciados&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#removidos-e-depreciados&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;mutação-de-campos-final-por-reflexão-passa-a-emitir-aviso&quot;&gt;Mutação de campos final por reflexão passa a emitir aviso&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#mutação-de-campos-final-por-reflexão-passa-a-emitir-aviso&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Chegou em:&lt;/strong&gt; Java 26 (final, &lt;a href=&quot;https://openjdk.org/jeps/500&quot;&gt;JEP 500&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;O problema.&lt;/strong&gt; Desde o JDK 5, &lt;code&gt;Field.setAccessible(true)&lt;/code&gt; seguido de &lt;code&gt;Field.set(...)&lt;/code&gt; altera até campos &lt;code&gt;final&lt;/code&gt;. Com isso, nem a JVM nem quem lê o código podem confiar que um &lt;code&gt;final&lt;/code&gt; de instância nunca muda. Para a JVM, isso bloqueia otimizações como o &lt;strong&gt;constant folding&lt;/strong&gt;, em que o compilador JIT troca a leitura do campo pelo próprio valor (é o que dá desempenho às &lt;a href=&quot;#lazy-constants&quot;&gt;Lazy Constants&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;O que mudou.&lt;/strong&gt; No Java 26, alterar um campo &lt;code&gt;final&lt;/code&gt; por reflexão ainda funciona, mas gera um &lt;strong&gt;aviso&lt;/strong&gt;, no máximo um por módulo. A JEP prevê que uma versão futura passe a &lt;strong&gt;lançar exceção&lt;/strong&gt; por padrão. O comportamento é controlado por &lt;code&gt;--illegal-final-field-mutation=allow|warn|debug|deny&lt;/code&gt; (&lt;code&gt;warn&lt;/code&gt; é o padrão no 26), e a permissão é dada explicitamente com &lt;code&gt;--enable-final-field-mutation=ALL-UNNAMED&lt;/code&gt; ou com uma lista de módulos. &lt;code&gt;--add-opens&lt;/code&gt;, a opção usada desde o &lt;a href=&quot;https://cesarschutz.com.br/posts/java-17/#encapsulamento-forte-dos-internos-do-jdk&quot;&gt;encapsulamento forte do Java 16 e 17&lt;/a&gt; para liberar reflexão profunda, não basta para evitar o aviso.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;FinalMutavel.java&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; java.lang.reflect.Field;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;FinalMutavel&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;Preco&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;final&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;long&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; centavos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;Preco&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;long&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;centavos&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) { &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;.centavos &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; centavos; }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;long&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;centavos&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;() { &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; centavos; }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;main&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;[] &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;args&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;throws&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; Exception {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;Preco preco &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;Preco&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;1_000&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;Field campo &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; Preco.class.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;getDeclaredField&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;centavos&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;campo.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;setAccessible&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;);   &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// continua funcionando como antes&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line highlight mark&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;campo.&lt;/span&gt;&lt;span style=&quot;--0:#c2a8f3;--1:#613aa9&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(preco, &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#004fa9&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;);         &lt;/span&gt;&lt;span style=&quot;--0:#afb5b9;--1:#4d545b&quot;&gt;// Java 26+: gera WARNING (padrão warn)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;IO.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(preco.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;centavos&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;());&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Saída no Temurin 26.0.2:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;saída&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#e1e4e8;--1:#24292e&quot;&gt;WARNING: Final field centavos in class FinalMutavel$Preco has been mutated reflectively by class FinalMutavel in unnamed module @525b461a (file:/w/FinalMutavel.java)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#e1e4e8;--1:#24292e&quot;&gt;WARNING: Use --enable-final-field-mutation=ALL-UNNAMED to avoid a warning&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#e1e4e8;--1:#24292e&quot;&gt;WARNING: Mutating final fields will be blocked in a future release unless final field mutation is enabled&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#e1e4e8;--1:#24292e&quot;&gt;1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Cuidados.&lt;/strong&gt; Com &lt;code&gt;--illegal-final-field-mutation=deny&lt;/code&gt;, o mesmo código lança &lt;code&gt;IllegalAccessException&lt;/code&gt;. A JEP recomenda rodar os testes com &lt;code&gt;deny&lt;/code&gt; desde já para achar quem faz isso, e em geral o culpado é uma biblioteca, não a aplicação. Outra forma de encontrar é o evento JFR &lt;code&gt;jdk.FinalFieldMutation&lt;/code&gt;. Para bibliotecas de serialização, a JEP recomenda &lt;code&gt;sun.reflect.ReflectionFactory&lt;/code&gt; em vez de reflexão profunda.&lt;/p&gt;
&lt;h3 id=&quot;applet-api-removida&quot;&gt;Applet API removida&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#applet-api-removida&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Chegou em:&lt;/strong&gt; Java 9 (depreciado, &lt;a href=&quot;https://openjdk.org/jeps/289&quot;&gt;JEP 289&lt;/a&gt;) → Java 17 (depreciado para remoção, &lt;a href=&quot;https://openjdk.org/jeps/398&quot;&gt;JEP 398&lt;/a&gt;) → Java 26 (removido, &lt;a href=&quot;https://openjdk.org/jeps/504&quot;&gt;JEP 504&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;Os navegadores já não executam applets, e desde o Java 11, quando o &lt;code&gt;appletviewer&lt;/code&gt; foi removido, o JDK não tem mais como rodá-los (&lt;a href=&quot;https://openjdk.org/jeps/504&quot;&gt;JEP 504&lt;/a&gt;; veja também &lt;a href=&quot;https://cesarschutz.com.br/posts/java-11/#nashorn-pack200-cms-e-applet-api&quot;&gt;Nashorn, Pack200, CMS e Applet API no post do Java 11&lt;/a&gt;). Faltava remover a API. No Java 26 saíram o pacote &lt;code&gt;java.applet&lt;/code&gt; inteiro, &lt;code&gt;javax.swing.JApplet&lt;/code&gt;, &lt;code&gt;java.beans.AppletInitializer&lt;/code&gt; e os membros de &lt;code&gt;java.beans.Beans&lt;/code&gt; e &lt;code&gt;javax.swing.RepaintManager&lt;/code&gt; que dependiam deles. Um efeito colateral: &lt;code&gt;URL.getContent()&lt;/code&gt; e &lt;code&gt;URLConnection.getContent()&lt;/code&gt; não devolvem mais &lt;code&gt;java.applet.AudioClip&lt;/code&gt; para conteúdo de áudio. Para tocar áudio, a JEP aponta a &lt;code&gt;javax.sound.SoundClip&lt;/code&gt;, introduzida no Java 25.&lt;/p&gt;
&lt;h3 id=&quot;outras-remoções&quot;&gt;Outras remoções&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#outras-remoções&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;table-wrap&quot;&gt;

















































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Removido&lt;/th&gt;&lt;th&gt;Versão&lt;/th&gt;&lt;th&gt;Fonte&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;Thread.stop()&lt;/code&gt;: código que chama não compila, e binários antigos recebem &lt;code&gt;NoSuchMethodError&lt;/code&gt;&lt;/td&gt;&lt;td&gt;26&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://www.oracle.com/java/technologies/javase/26-relnote-issues.html&quot;&gt;Notas do 26&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Ferramenta &lt;code&gt;jrunscript&lt;/code&gt; e módulo &lt;code&gt;jdk.jsobject&lt;/code&gt; (este segue no JavaFX)&lt;/td&gt;&lt;td&gt;26&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://www.oracle.com/java/technologies/javase/26-relnote-issues.html&quot;&gt;Notas do 26&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Suporte a InfiniBand SDP, &lt;code&gt;setTTL&lt;/code&gt;/&lt;code&gt;getTTL&lt;/code&gt; de &lt;code&gt;MulticastSocket&lt;/code&gt; e &lt;code&gt;DatagramSocketImpl&lt;/code&gt; e &lt;code&gt;MulticastSocket.send(DatagramPacket, byte)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;26&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://www.oracle.com/java/technologies/javase/26-relnote-issues.html&quot;&gt;Notas do 26&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;JVM Compiler Interface (JVMCI, a interface para plugar na JVM um compilador JIT escrito em Java, &lt;a href=&quot;https://openjdk.org/jeps/243&quot;&gt;JEP 243&lt;/a&gt;): módulos &lt;code&gt;jdk.internal.vm.ci&lt;/code&gt;, &lt;code&gt;jdk.graal.compiler&lt;/code&gt; e &lt;code&gt;jdk.graal.compiler.management&lt;/code&gt;, flags &lt;code&gt;*JVMCI*&lt;/code&gt; e &lt;code&gt;-XX:+UseGraalJIT&lt;/code&gt;&lt;/td&gt;&lt;td&gt;27&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://jdk.java.net/27/release-notes&quot;&gt;Notas do 27&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Opções &lt;code&gt;-noclassgc&lt;/code&gt;, &lt;code&gt;-noverify&lt;/code&gt;, &lt;code&gt;-verifyremote&lt;/code&gt; e &lt;code&gt;-Xverify:none&lt;/code&gt;&lt;/td&gt;&lt;td&gt;27&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://jdk.java.net/27/release-notes&quot;&gt;Notas do 27&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;ThreadPoolExecutor.finalize()&lt;/code&gt;&lt;/td&gt;&lt;td&gt;27&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://jdk.java.net/27/release-notes&quot;&gt;Notas do 27&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Mecanismo &lt;code&gt;VFORK&lt;/code&gt; de &lt;code&gt;jdk.lang.Process.launchMechanism&lt;/code&gt; (Linux) e a propriedade &lt;code&gt;java.locale.useOldISOCodes&lt;/code&gt;&lt;/td&gt;&lt;td&gt;27&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://jdk.java.net/27/release-notes&quot;&gt;Notas do 27&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;ffdhe6144&lt;/code&gt; e &lt;code&gt;ffdhe8192&lt;/code&gt; saem da lista padrão de named groups TLS&lt;/td&gt;&lt;td&gt;27&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://jdk.java.net/27/release-notes&quot;&gt;Notas do 27&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;
&lt;h3 id=&quot;depreciações&quot;&gt;Depreciações&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#depreciações&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Java 26:&lt;/strong&gt; &lt;code&gt;java.net.SocketPermission&lt;/code&gt; e &lt;code&gt;Socket.setPerformancePreferences&lt;/code&gt; (e os equivalentes em &lt;code&gt;SocketImpl&lt;/code&gt; e &lt;code&gt;ServerSocket&lt;/code&gt;) foram depreciados para remoção. Também foram depreciadas as flags &lt;code&gt;-Xmaxjitcodesize&lt;/code&gt;, &lt;code&gt;AlwaysActAsServerClassMachine&lt;/code&gt;, &lt;code&gt;NeverActAsServerClassMachine&lt;/code&gt;, &lt;code&gt;AggressiveHeap&lt;/code&gt; e &lt;code&gt;MaxRAM&lt;/code&gt;. No caso de &lt;code&gt;MaxRAM&lt;/code&gt;, o valor padrão também deixou de existir, e o dimensionamento do heap usa a memória disponível (&lt;a href=&quot;https://www.oracle.com/java/technologies/javase/26-relnote-issues.html&quot;&gt;notas do 26&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Java 27:&lt;/strong&gt; o alias &lt;code&gt;-XX:InitiatingHeapOccupancyPercent&lt;/code&gt; foi depreciado (&lt;a href=&quot;https://jdk.java.net/27/release-notes&quot;&gt;notas do 27&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Java 28 (ainda não lançado):&lt;/strong&gt; port macOS/x64 depreciado para remoção (&lt;a href=&quot;https://openjdk.org/jeps/541&quot;&gt;JEP 541&lt;/a&gt;). Segundo a JEP, os engenheiros da Oracle deixam de manter esse port a partir do JDK 27.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;ainda-em-preview-ou-incubadora&quot;&gt;Ainda em preview ou incubadora&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#ainda-em-preview-ou-incubadora&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Nenhum destes recursos é definitivo: todos exigem &lt;code&gt;--enable-preview&lt;/code&gt; (ou &lt;code&gt;--add-modules&lt;/code&gt;, no caso da incubadora) e mudaram de API entre uma versão e outra. Todos já existiam como preview ou incubadora no Java 25; cada seção aponta para a explicação original no post do Java 25 e mostra o que mudou desde então. Os exemplos refletem o Java 27.&lt;/p&gt;
&lt;h3 id=&quot;structured-concurrency&quot;&gt;Structured Concurrency&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#structured-concurrency&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Chegou em:&lt;/strong&gt; Java 25 (5ª preview, &lt;a href=&quot;https://openjdk.org/jeps/505&quot;&gt;JEP 505&lt;/a&gt;) → Java 26 (6ª preview, &lt;a href=&quot;https://openjdk.org/jeps/525&quot;&gt;JEP 525&lt;/a&gt;) → Java 27 (7ª preview, &lt;a href=&quot;https://openjdk.org/jeps/533&quot;&gt;JEP 533&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;As primeiras versões estão em &lt;a href=&quot;https://cesarschutz.com.br/posts/java-21/#structured-concurrency&quot;&gt;Structured Concurrency no post do Java 21&lt;/a&gt; e &lt;a href=&quot;https://cesarschutz.com.br/posts/java-25/#structured-concurrency&quot;&gt;no post do Java 25&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;O problema.&lt;/strong&gt; Com &lt;code&gt;ExecutorService&lt;/code&gt;, nada liga as tarefas ao método que as disparou: se uma falha, as outras continuam; se quem espera é interrompido, as subtarefas nem ficam sabendo; e o thread dump não mostra quem é filho de quem.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Como funciona.&lt;/strong&gt; &lt;code&gt;StructuredTaskScope&lt;/code&gt; trata um grupo de subtarefas como uma unidade presa a um bloco &lt;code&gt;try&lt;/code&gt;. A thread que abre o escopo, chamada de thread dona, dispara as subtarefas com &lt;code&gt;fork&lt;/code&gt; (por padrão, cada uma numa virtual thread), espera tudo com &lt;code&gt;join&lt;/code&gt; e fecha o escopo ao sair do bloco. A política de conclusão fica num &lt;code&gt;Joiner&lt;/code&gt;. Na política padrão, se uma subtarefa falhar, as outras são canceladas. O &lt;code&gt;close()&lt;/code&gt; sempre espera as threads terminarem, então nenhuma sobra depois do bloco. No thread dump em JSON (&lt;code&gt;jcmd &amp;#x3C;pid&gt; Thread.dump_to_file -format=json &amp;#x3C;arquivo&gt;&lt;/code&gt;), a hierarquia de escopos aparece.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cesarschutz.com.br/posts/java-29/structured-concurrency.svg&quot; alt=&quot;Diagrama do StructuredTaskScope no Java 27: a thread dona abre o escopo, dispara três subtarefas em virtual threads e chama join; com os Joiners prontos, os três desfechos são sucesso com resultado, falha de uma subtarefa com ExecutionException e prazo estourado com ExecutionException causada por CancelledByTimeoutException&quot;&gt;&lt;/p&gt;
&lt;p&gt;O diagrama mostra os três desfechos possíveis do &lt;code&gt;join()&lt;/code&gt; com os &lt;code&gt;Joiner&lt;/code&gt;s prontos do Java 27. O exemplo abaixo cobre a política padrão e um &lt;code&gt;Joiner&lt;/code&gt; com prazo:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;Checkout.java&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; java.time.Duration;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; java.util.List;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; java.util.concurrent.ExecutionException;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; java.util.concurrent.StructuredTaskScope;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; java.util.concurrent.StructuredTaskScope.CancelledByTimeoutException;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; java.util.concurrent.StructuredTaskScope.Joiner;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; java.util.concurrent.StructuredTaskScope.Subtask;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;Checkout&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;Resumo&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(String cliente, &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; itens) {}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; String &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;buscarCliente&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;throws&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; InterruptedException {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;Thread.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;sleep&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;100&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;ana&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;contarItens&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;throws&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; InterruptedException {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;Thread.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;sleep&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;150&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; String &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;consultarEstoque&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(String &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;sku&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;throws&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; InterruptedException {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;Thread.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;sleep&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(sku.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;equals&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;lento&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;5_000&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;50&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; sku &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;: disponível&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// Política padrão: se uma subtarefa falhar, as outras são canceladas&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; Resumo &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;carregar&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;throws&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; ExecutionException, InterruptedException {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line highlight mark&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#fb99a3;--1:#982934&quot;&gt;try&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#fb99a3;--1:#982934&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; scope &lt;/span&gt;&lt;span style=&quot;--0:#fb99a3;--1:#982934&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; StructuredTaskScope.&lt;/span&gt;&lt;span style=&quot;--0:#c2a8f3;--1:#613aa9&quot;&gt;open&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;()) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line highlight mark&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;Subtask&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#fb99a3;--1:#982934&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&gt; cliente &lt;/span&gt;&lt;span style=&quot;--0:#fb99a3;--1:#982934&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; scope.&lt;/span&gt;&lt;span style=&quot;--0:#c2a8f3;--1:#613aa9&quot;&gt;fork&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(() &lt;/span&gt;&lt;span style=&quot;--0:#fb99a3;--1:#982934&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#c2a8f3;--1:#613aa9&quot;&gt;buscarCliente&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;());&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line highlight mark&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;Subtask&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#fb99a3;--1:#982934&quot;&gt;Integer&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&gt; itens &lt;/span&gt;&lt;span style=&quot;--0:#fb99a3;--1:#982934&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; scope.&lt;/span&gt;&lt;span style=&quot;--0:#c2a8f3;--1:#613aa9&quot;&gt;fork&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(() &lt;/span&gt;&lt;span style=&quot;--0:#fb99a3;--1:#982934&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#c2a8f3;--1:#613aa9&quot;&gt;contarItens&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;());&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line highlight mark&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line highlight mark&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;scope.&lt;/span&gt;&lt;span style=&quot;--0:#c2a8f3;--1:#613aa9&quot;&gt;join&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(); &lt;/span&gt;&lt;span style=&quot;--0:#afb5b9;--1:#4d545b&quot;&gt;// Java 27: lança ExecutionException se alguma falhar&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line highlight mark&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line highlight mark&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#fb99a3;--1:#982934&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#fb99a3;--1:#982934&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#c2a8f3;--1:#613aa9&quot;&gt;Resumo&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(cliente.&lt;/span&gt;&lt;span style=&quot;--0:#c2a8f3;--1:#613aa9&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(), itens.&lt;/span&gt;&lt;span style=&quot;--0:#c2a8f3;--1:#613aa9&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;());&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line highlight mark&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// Todas precisam dar certo dentro do prazo; o resultado já vem como lista&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; List&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;estoque&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(List&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;skus&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, Duration &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;prazo&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;throws&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; ExecutionException, InterruptedException {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line highlight mark&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#fb99a3;--1:#982934&quot;&gt;try&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#fb99a3;--1:#982934&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; scope &lt;/span&gt;&lt;span style=&quot;--0:#fb99a3;--1:#982934&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; StructuredTaskScope.&lt;/span&gt;&lt;span style=&quot;--0:#c2a8f3;--1:#613aa9&quot;&gt;open&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line highlight mark&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;Joiner.&lt;/span&gt;&lt;span style=&quot;--0:#fb99a3;--1:#982934&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#fb99a3;--1:#982934&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;--0:#c2a8f3;--1:#613aa9&quot;&gt;allSuccessfulOrThrow&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line highlight mark&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;cf &lt;/span&gt;&lt;span style=&quot;--0:#fb99a3;--1:#982934&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; cf.&lt;/span&gt;&lt;span style=&quot;--0:#c2a8f3;--1:#613aa9&quot;&gt;withTimeout&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(prazo))) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line highlight mark&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;skus.&lt;/span&gt;&lt;span style=&quot;--0:#c2a8f3;--1:#613aa9&quot;&gt;forEach&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(sku &lt;/span&gt;&lt;span style=&quot;--0:#fb99a3;--1:#982934&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; scope.&lt;/span&gt;&lt;span style=&quot;--0:#c2a8f3;--1:#613aa9&quot;&gt;fork&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(() &lt;/span&gt;&lt;span style=&quot;--0:#fb99a3;--1:#982934&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#c2a8f3;--1:#613aa9&quot;&gt;consultarEstoque&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(sku)));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line highlight mark&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#fb99a3;--1:#982934&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; scope.&lt;/span&gt;&lt;span style=&quot;--0:#c2a8f3;--1:#613aa9&quot;&gt;join&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;main&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;[] &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;args&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;throws&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; Exception {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;IO.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;carregar&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;());&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;IO.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;estoque&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(List.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;a1&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;b2&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;), Duration.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;ofSeconds&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;)));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;try&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;estoque&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(List.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;a1&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;lento&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;), Duration.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;ofMillis&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;300&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;catch&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (ExecutionException &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (e.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;getCause&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;instanceof&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; CancelledByTimeoutException) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;IO.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;prazo estourado: subtarefas canceladas&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Para rodar no Java 27: &lt;code&gt;java --enable-preview --source 27 Checkout.java&lt;/code&gt;. Pela API do JDK 27, a saída esperada é:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;saída&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#e1e4e8;--1:#24292e&quot;&gt;Resumo[cliente=ana, itens=3]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#e1e4e8;--1:#24292e&quot;&gt;[a1: disponível, b2: disponível]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#e1e4e8;--1:#24292e&quot;&gt;prazo estourado: subtarefas canceladas&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;A lista do segundo passo vem na ordem em que as subtarefas foram disparadas com &lt;code&gt;fork&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;O que mudou no caminho.&lt;/strong&gt; Cada preview mexeu na API, e código escrito para uma versão costuma não compilar na seguinte:&lt;/p&gt;
&lt;div class=&quot;table-wrap&quot;&gt;




















&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Versão&lt;/th&gt;&lt;th&gt;Mudanças na API&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Java 25 (&lt;a href=&quot;https://openjdk.org/jeps/505&quot;&gt;JEP 505&lt;/a&gt;)&lt;/td&gt;&lt;td&gt;Os construtores públicos deram lugar às fábricas estáticas &lt;code&gt;open(...)&lt;/code&gt; e a política passou para o &lt;code&gt;Joiner&lt;/code&gt;. Em caso de falha, &lt;code&gt;join()&lt;/code&gt; lançava &lt;code&gt;FailedException&lt;/code&gt;; com prazo estourado, &lt;code&gt;TimeoutException&lt;/code&gt;.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Java 26 (&lt;a href=&quot;https://openjdk.org/jeps/525&quot;&gt;JEP 525&lt;/a&gt;)&lt;/td&gt;&lt;td&gt;Novo &lt;code&gt;Joiner.onTimeout()&lt;/code&gt;, para um &lt;code&gt;Joiner&lt;/code&gt; devolver resultado quando o prazo estoura. &lt;code&gt;allSuccessfulOrThrow()&lt;/code&gt; passou a devolver uma lista de resultados, e não mais um stream de subtarefas. &lt;code&gt;anySuccessfulResultOrThrow()&lt;/code&gt; foi renomeado para &lt;code&gt;anySuccessfulOrThrow()&lt;/code&gt;. O &lt;code&gt;open&lt;/code&gt; que recebe &lt;code&gt;Joiner&lt;/code&gt; e configuração passou a aceitar &lt;code&gt;UnaryOperator&lt;/code&gt; em vez de &lt;code&gt;Function&lt;/code&gt;. As exceções de &lt;code&gt;join()&lt;/code&gt; continuaram as mesmas.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Java 27 (&lt;a href=&quot;https://openjdk.org/jeps/533&quot;&gt;JEP 533&lt;/a&gt;)&lt;/td&gt;&lt;td&gt;&lt;code&gt;StructuredTaskScope&lt;/code&gt; e &lt;code&gt;Joiner&lt;/code&gt; ganharam um terceiro parâmetro de tipo, &lt;code&gt;R_X&lt;/code&gt;, com a exceção que &lt;code&gt;join()&lt;/code&gt; pode lançar. As fábricas prontas passaram a lançar &lt;code&gt;ExecutionException&lt;/code&gt;, e há sobrecargas que recebem uma &lt;code&gt;Function&lt;/code&gt; para gerar outra exceção. &lt;code&gt;FailedException&lt;/code&gt; e &lt;code&gt;TimeoutException&lt;/code&gt; deixaram de existir. &lt;code&gt;awaitAll()&lt;/code&gt; foi removido. &lt;code&gt;onTimeout()&lt;/code&gt; virou &lt;code&gt;timeout()&lt;/code&gt;, e o estouro de prazo chega como exceção com causa &lt;code&gt;CancelledByTimeoutException&lt;/code&gt;. Também entrou o &lt;code&gt;open(UnaryOperator)&lt;/code&gt;.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Na prática, o tratamento de erro escrito para o 26 precisa mudar no 27:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;TratamentoDeErro.java&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;try&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; scope &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; StructuredTaskScope.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;open&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;()) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// ...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line highlight del&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;--0:#fa96a1;--1:#952933&quot;&gt;catch&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (StructuredTaskScope.FailedException &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#883b05&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) {   &lt;/span&gt;&lt;span style=&quot;--0:#aeb3b8;--1:#4c5259&quot;&gt;// Java 26&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line highlight ins&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;--0:#fb99a3;--1:#982934&quot;&gt;catch&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (ExecutionException &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#8b3c06&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) {                    &lt;/span&gt;&lt;span style=&quot;--0:#afb5b9;--1:#4d545b&quot;&gt;// Java 27&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;Throwable causa &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; e.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;getCause&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;();                 &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// exceção da subtarefa que falhou&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Um &lt;code&gt;Joiner&lt;/code&gt; próprio implementa &lt;code&gt;result()&lt;/code&gt; e, a partir do 27, &lt;code&gt;timeout()&lt;/code&gt;; &lt;code&gt;onFork&lt;/code&gt; e &lt;code&gt;onComplete&lt;/code&gt; têm implementação default. As assinaturas completas estão na JEP 533 e no &lt;a href=&quot;https://github.com/openjdk/jdk/blob/jdk-27-ga/src/java.base/share/classes/java/util/concurrent/StructuredTaskScope.java&quot;&gt;código-fonte do &lt;code&gt;StructuredTaskScope&lt;/code&gt; na tag &lt;code&gt;jdk-27-ga&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Existe uma JEP candidata, a &lt;a href=&quot;https://openjdk.org/jeps/543&quot;&gt;JEP 543&lt;/a&gt;, que propõe finalizar a API no Java 28 sem outras mudanças. Em 16/09/2026 ela ainda não tinha alvo no 28.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Quando usar.&lt;/strong&gt; Quando uma operação se divide em subtarefas concorrentes que só fazem sentido juntas, como buscar dados de vários serviços para montar uma resposta. Enquanto a API estiver em preview, concentre o uso em poucos pontos do código: a cada versão do JDK, é ali que o ajuste vai ser necessário.&lt;/p&gt;
&lt;h3 id=&quot;tipos-primitivos-em-patterns-instanceof-e-switch&quot;&gt;Tipos primitivos em patterns, instanceof e switch&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#tipos-primitivos-em-patterns-instanceof-e-switch&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Chegou em:&lt;/strong&gt; Java 25 (3ª preview, &lt;a href=&quot;https://openjdk.org/jeps/507&quot;&gt;JEP 507&lt;/a&gt;) → Java 26 (4ª preview, &lt;a href=&quot;https://openjdk.org/jeps/530&quot;&gt;JEP 530&lt;/a&gt;) → Java 27 (5ª preview, &lt;a href=&quot;https://openjdk.org/jeps/532&quot;&gt;JEP 532&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;A versão do Java 25 está em &lt;a href=&quot;https://cesarschutz.com.br/posts/java-25/#tipos-primitivos-em-padr%C3%B5es-instanceof-e-switch&quot;&gt;Tipos primitivos em padrões, instanceof e switch no post do Java 25&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;O problema.&lt;/strong&gt; Converter um primitivo para outro menor, como &lt;code&gt;int&lt;/code&gt; para &lt;code&gt;byte&lt;/code&gt;, é silencioso: se o valor não cabe, o cast corta bits e o erro segue adiante sem aviso. O &lt;code&gt;instanceof&lt;/code&gt; sempre serviu para perguntar “é seguro fazer este cast?”, mas só funcionava com tipos de referência. Um &lt;code&gt;switch&lt;/code&gt; também não aceitava &lt;code&gt;long&lt;/code&gt;, &lt;code&gt;float&lt;/code&gt;, &lt;code&gt;double&lt;/code&gt; nem &lt;code&gt;boolean&lt;/code&gt; como seletor.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Como funciona.&lt;/strong&gt; Com o recurso habilitado, &lt;code&gt;instanceof&lt;/code&gt; e &lt;code&gt;switch&lt;/code&gt; aceitam tipos primitivos em qualquer posição de pattern. O teste vale &lt;code&gt;true&lt;/code&gt; quando a conversão é &lt;strong&gt;exata&lt;/strong&gt;, ou seja, quando nenhuma informação se perde. Com &lt;code&gt;int i = 1000&lt;/code&gt;, &lt;code&gt;i instanceof byte&lt;/code&gt; é &lt;code&gt;false&lt;/code&gt;. Com &lt;code&gt;i = 16_777_217&lt;/code&gt;, &lt;code&gt;i instanceof float&lt;/code&gt; também é &lt;code&gt;false&lt;/code&gt;, porque o &lt;code&gt;float&lt;/code&gt; não representa esse inteiro sem perder precisão. O &lt;code&gt;switch&lt;/code&gt; passa a funcionar com todos os tipos primitivos e com os wrappers correspondentes. Um &lt;code&gt;switch&lt;/code&gt; sobre &lt;code&gt;boolean&lt;/code&gt; que trata &lt;code&gt;true&lt;/code&gt; e &lt;code&gt;false&lt;/code&gt; já é exaustivo.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;O que mudou no caminho.&lt;/strong&gt; A JEP 530 (Java 26) mudou duas coisas: melhorou a definição de conversão “incondicionalmente exata” e deixou mais rígida a checagem de dominância no &lt;code&gt;switch&lt;/code&gt;. Com isso, o compilador passa a rejeitar &lt;code&gt;case&lt;/code&gt; que nunca seriam alcançados, e alguns &lt;code&gt;switch&lt;/code&gt; que compilavam no Java 25 deixam de compilar. A JEP 532 (Java 27) repete o preview sem mudanças, então quem já ajustou o código para o 26 não precisa mexer de novo.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;PadroesPrimitivos.java&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;PadroesPrimitivos&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// instanceof com tipo primitivo: true só se a conversão for exata&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; String &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;classificar&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;valor&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (valor &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;instanceof&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;byte&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; b) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;cabe em byte: &quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; b;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;precisa de int: &quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; valor;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// switch sobre double, com constante e guarda&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; String &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;descrever&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;double&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;temperatura&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;switch&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (temperatura) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;case&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;0d&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;zero&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;case&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;double&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; t when t &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;negativa: &quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; t;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;case&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;double&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; t &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;positiva: &quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; t;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// switch sobre boolean: true + false já é exaustivo&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; String &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;estado&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;boolean&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;ativo&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;switch&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (ativo) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;case&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;ligado&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;case&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;desligado&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;main&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;[] &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;args&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;IO.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;classificar&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;42&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;));     &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// cabe em byte: 42&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;IO.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;classificar&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;1000&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;));   &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// precisa de int: 1000&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;IO.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;descrever&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;3.5&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;));     &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// negativa: -3.5&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;IO.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;estado&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;));        &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// ligado&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;long&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; grande &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;16_777_217L&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;;       &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// 2^24 + 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;IO.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(grande &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;instanceof&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;float&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;);  &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// false: float perderia precisão&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;IO.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(grande &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;instanceof&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;double&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;); &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// true&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Para rodar: &lt;code&gt;java --enable-preview --source 27 PadroesPrimitivos.java&lt;/code&gt; (no Java 26, &lt;code&gt;--source 26&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;A checagem de dominância mais rígida também pega constantes que um pattern anterior já cobre. O trecho abaixo compila no Java 25 com &lt;code&gt;--enable-preview&lt;/code&gt; e é rejeitado a partir do 26:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;Dominancia.java&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;teste&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; x) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;switch&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (x) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;case&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;float&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; f &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; IO.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;float&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line highlight mark&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#afb5b9;--1:#4d545b&quot;&gt;// erro: &quot;this case label is dominated by a preceding case label&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line highlight mark&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#fb99a3;--1:#982934&quot;&gt;case&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#004fa9&quot;&gt;16_777_216&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#fb99a3;--1:#982934&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; IO.&lt;/span&gt;&lt;span style=&quot;--0:#c2a8f3;--1:#613aa9&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;constante&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; IO.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;outro&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h3 id=&quot;lazy-constants&quot;&gt;Lazy Constants&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#lazy-constants&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Chegou em:&lt;/strong&gt; Java 25 (preview, &lt;a href=&quot;https://openjdk.org/jeps/502&quot;&gt;JEP 502&lt;/a&gt;) → Java 26 (2ª preview, &lt;a href=&quot;https://openjdk.org/jeps/526&quot;&gt;JEP 526&lt;/a&gt;) → Java 27 (3ª preview, &lt;a href=&quot;https://openjdk.org/jeps/531&quot;&gt;JEP 531&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;No Java 25, a API se chamava Stable Values (veja &lt;a href=&quot;https://cesarschutz.com.br/posts/java-25/#stable-values&quot;&gt;Stable Values no post do Java 25&lt;/a&gt;); o nome Lazy Constants veio no Java 26.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;O problema.&lt;/strong&gt; Um campo &lt;code&gt;final&lt;/code&gt; precisa ser atribuído no construtor ou no inicializador estático, ou seja, cedo. Se o valor é caro de montar (um logger que lê configuração, uma conexão, um cache), a aplicação paga esse custo na subida, mesmo que nunca use o valor. As saídas de sempre têm seus problemas: o padrão da classe holder só serve para campos &lt;code&gt;static&lt;/code&gt;, o double-checked locking exige &lt;code&gt;volatile&lt;/code&gt; e é fácil de errar, e o &lt;code&gt;ConcurrentHashMap.computeIfAbsent&lt;/code&gt; impede que a JVM trate o valor como constante.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Como funciona.&lt;/strong&gt; Um &lt;code&gt;java.lang.LazyConstant&amp;#x3C;T&gt;&lt;/code&gt; nasce vazio, com uma função de cálculo. O primeiro &lt;code&gt;get()&lt;/code&gt; executa a função e guarda o resultado. A função roda &lt;strong&gt;no máximo uma vez&lt;/strong&gt;, mesmo com várias threads chamando &lt;code&gt;get()&lt;/code&gt; ao mesmo tempo, e depois disso o conteúdo não muda. Segundo a JEP, o conteúdo fica num campo com a anotação interna &lt;code&gt;@Stable&lt;/code&gt;; se a lazy constant estiver num campo &lt;code&gt;final&lt;/code&gt;, a JVM pode aplicar constant folding (explicado na seção da &lt;a href=&quot;#muta%C3%A7%C3%A3o-de-campos-final-por-reflex%C3%A3o-passa-a-emitir-aviso&quot;&gt;JEP 500&lt;/a&gt;) como faria com um &lt;code&gt;final&lt;/code&gt; comum. Existem também versões preguiçosas das coleções: &lt;code&gt;List.ofLazy&lt;/code&gt;, &lt;code&gt;Map.ofLazy&lt;/code&gt; e, a partir do Java 27, &lt;code&gt;Set.ofLazy&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cesarschutz.com.br/posts/java-29/lazy-constant.svg&quot; alt=&quot;Diagrama do ciclo de vida de uma LazyConstant (criada, primeiro get, inicializada) e comparação entre campo final, LazyConstant e campo não final em número de atribuições, momento do cálculo, constant folding e escrita concorrente&quot;&gt;&lt;/p&gt;
&lt;p&gt;O diagrama mostra o ciclo de vida de uma lazy constant e a comparação que a JEP 531 faz com campos &lt;code&gt;final&lt;/code&gt; e não &lt;code&gt;final&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;Aplicacao.java&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; java.util.EnumSet;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; java.util.List;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; java.util.Map;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; java.util.Set;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;Aplicacao&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;Conexao&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(String url) {}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;Worker&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; id) {}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;Taxa&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(String moeda, &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;double&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; valor) {}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;enum&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;Opcao&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;VERBOSE&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;DRY_RUN&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;STRICT&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// Computado no primeiro get(), no máximo uma vez, mesmo com várias threads&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line highlight mark&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#fb99a3;--1:#982934&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#fb99a3;--1:#982934&quot;&gt;final&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; LazyConstant&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#fb99a3;--1:#982934&quot;&gt;Conexao&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&gt; CONEXAO &lt;/span&gt;&lt;span style=&quot;--0:#fb99a3;--1:#982934&quot;&gt;=&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line highlight mark&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;LazyConstant.&lt;/span&gt;&lt;span style=&quot;--0:#c2a8f3;--1:#613aa9&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(() &lt;/span&gt;&lt;span style=&quot;--0:#fb99a3;--1:#982934&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#c2a8f3;--1:#613aa9&quot;&gt;abrirConexao&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;jdbc:postgresql://db/app&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// Lista de tamanho fixo: cada posição é computada quando acessada&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line highlight mark&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#fb99a3;--1:#982934&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#fb99a3;--1:#982934&quot;&gt;final&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; List&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#fb99a3;--1:#982934&quot;&gt;Worker&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&gt; WORKERS &lt;/span&gt;&lt;span style=&quot;--0:#fb99a3;--1:#982934&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; List.&lt;/span&gt;&lt;span style=&quot;--0:#c2a8f3;--1:#613aa9&quot;&gt;ofLazy&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#004fa9&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, Worker&lt;/span&gt;&lt;span style=&quot;--0:#fb99a3;--1:#982934&quot;&gt;::new&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// Mapa com chaves conhecidas: cada valor é computado quando lido&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line highlight mark&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#fb99a3;--1:#982934&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#fb99a3;--1:#982934&quot;&gt;final&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; Map&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#fb99a3;--1:#982934&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#fb99a3;--1:#982934&quot;&gt;Taxa&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&gt; TAXAS &lt;/span&gt;&lt;span style=&quot;--0:#fb99a3;--1:#982934&quot;&gt;=&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line highlight mark&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;Map.&lt;/span&gt;&lt;span style=&quot;--0:#c2a8f3;--1:#613aa9&quot;&gt;ofLazy&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(Set.&lt;/span&gt;&lt;span style=&quot;--0:#c2a8f3;--1:#613aa9&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;BRL&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;USD&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;), Aplicacao&lt;/span&gt;&lt;span style=&quot;--0:#fb99a3;--1:#982934&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;carregarTaxa);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// Java 27: a pertinência de cada candidato é decidida sob demanda&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line highlight mark&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#fb99a3;--1:#982934&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#fb99a3;--1:#982934&quot;&gt;final&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; Set&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#fb99a3;--1:#982934&quot;&gt;Opcao&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&gt; OPCOES &lt;/span&gt;&lt;span style=&quot;--0:#fb99a3;--1:#982934&quot;&gt;=&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line highlight mark&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;Set.&lt;/span&gt;&lt;span style=&quot;--0:#c2a8f3;--1:#613aa9&quot;&gt;ofLazy&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(EnumSet.&lt;/span&gt;&lt;span style=&quot;--0:#c2a8f3;--1:#613aa9&quot;&gt;allOf&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(Opcao.class), Aplicacao&lt;/span&gt;&lt;span style=&quot;--0:#fb99a3;--1:#982934&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;habilitada);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; Conexao &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;abrirConexao&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(String &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;url&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;IO.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;abrindo conexão (uma única vez)&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;Conexao&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(url);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; Taxa &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;carregarTaxa&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(String &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;moeda&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;IO.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;carregando taxa de &quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; moeda);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;Taxa&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(moeda, moeda.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;equals&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;BRL&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;1.0&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;5.4&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;boolean&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;habilitada&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(Opcao &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;opcao&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;IO.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;avaliando &quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; opcao);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; opcao &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; Opcao.DRY_RUN;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;main&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;[] &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;args&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;IO.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(CONEXAO.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;());      &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// computa aqui&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;IO.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(CONEXAO.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;());      &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// devolve o mesmo valor, sem recalcular&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;IO.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(WORKERS.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;));     &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// só o índice 2 é criado&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;IO.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(TAXAS.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;USD&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;));   &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// só USD é carregado; BRL, não&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;IO.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(OPCOES.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;contains&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(Opcao.DRY_RUN)); &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// só DRY_RUN é avaliado&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Para rodar no Java 27: &lt;code&gt;java --enable-preview --source 27 Aplicacao.java&lt;/code&gt;. A saída mostra que cada função de cálculo roda só quando o valor é pedido, e uma única vez:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;saída&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#e1e4e8;--1:#24292e&quot;&gt;abrindo conexão (uma única vez)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#e1e4e8;--1:#24292e&quot;&gt;Conexao[url=jdbc:postgresql://db/app]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#e1e4e8;--1:#24292e&quot;&gt;Conexao[url=jdbc:postgresql://db/app]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#e1e4e8;--1:#24292e&quot;&gt;Worker[id=2]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#e1e4e8;--1:#24292e&quot;&gt;carregando taxa de USD&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#e1e4e8;--1:#24292e&quot;&gt;Taxa[moeda=USD, valor=5.4]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#e1e4e8;--1:#24292e&quot;&gt;avaliando DRY_RUN&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#e1e4e8;--1:#24292e&quot;&gt;true&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;No Java 26, &lt;code&gt;Set.ofLazy&lt;/code&gt; não existe. Sem as linhas de &lt;code&gt;OPCOES&lt;/code&gt;, o exemplo roda com &lt;code&gt;--source 26&lt;/code&gt; no Temurin 26.0.2 e imprime as seis primeiras linhas acima.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Quando usar.&lt;/strong&gt; Lazy constants fazem sentido para valores caros que talvez nem sejam usados e que, depois de calculados, nunca mudam: configuração, conexões, loggers, tabelas de consulta. Enquanto a API estiver em preview, prefira usá-la em código que você controla e recompila a cada versão do JDK.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;O que mudou no caminho.&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Java 26 (JEP 526):&lt;/strong&gt; a API foi renomeada de &lt;code&gt;StableValue&lt;/code&gt; para &lt;code&gt;LazyConstant&lt;/code&gt; e ficou só com os casos de alto nível. Saíram os métodos de baixo nível &lt;code&gt;orElseSet&lt;/code&gt;, &lt;code&gt;setOrThrow&lt;/code&gt; e &lt;code&gt;trySet&lt;/code&gt;, e também as fábricas &lt;code&gt;function&lt;/code&gt; e &lt;code&gt;intFunction&lt;/code&gt;. As fábricas de coleções foram para &lt;code&gt;List.ofLazy&lt;/code&gt; e &lt;code&gt;Map.ofLazy&lt;/code&gt;, e &lt;code&gt;null&lt;/code&gt; deixou de ser aceito como valor calculado.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Java 27 (JEP 531):&lt;/strong&gt; saíram &lt;code&gt;isInitialized()&lt;/code&gt; e &lt;code&gt;orElse(...)&lt;/code&gt;, e entrou &lt;code&gt;Set.ofLazy(...)&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A JEP deixa claro que o ganho de constant folding depende de a JVM confiar em campos &lt;code&gt;final&lt;/code&gt;. Campos &lt;code&gt;static final&lt;/code&gt; já são confiáveis. A maioria dos campos &lt;code&gt;final&lt;/code&gt; de instância ainda pode ser alterada por reflexão, e a JEP cita a intenção de restringir isso no longo prazo, caminho que começou com a &lt;a href=&quot;#muta%C3%A7%C3%A3o-de-campos-final-por-reflex%C3%A3o-passa-a-emitir-aviso&quot;&gt;JEP 500&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;api-pem&quot;&gt;API PEM&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#api-pem&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Chegou em:&lt;/strong&gt; Java 25 (preview, &lt;a href=&quot;https://openjdk.org/jeps/470&quot;&gt;JEP 470&lt;/a&gt;) → Java 26 (2ª preview, &lt;a href=&quot;https://openjdk.org/jeps/524&quot;&gt;JEP 524&lt;/a&gt;) → Java 27 (3ª preview, &lt;a href=&quot;https://openjdk.org/jeps/538&quot;&gt;JEP 538&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;A primeira versão está em &lt;a href=&quot;https://cesarschutz.com.br/posts/java-25/#codifica%C3%A7%C3%A3o-pem-de-objetos-criptogr%C3%A1ficos&quot;&gt;Codificação PEM de objetos criptográficos no post do Java 25&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;O problema.&lt;/strong&gt; PEM é o formato de texto com &lt;code&gt;-----BEGIN ...-----&lt;/code&gt; usado para chaves, certificados e CRLs. Até aqui, o JDK não tinha uma API para ler e escrever esse formato: era preciso tirar cabeçalhos e decodificar Base64 à mão, ou recorrer a bibliotecas como o Bouncy Castle.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Como funciona.&lt;/strong&gt; &lt;code&gt;PEMEncoder&lt;/code&gt; e &lt;code&gt;PEMDecoder&lt;/code&gt; (em &lt;code&gt;java.security&lt;/code&gt;) são imutáveis, thread-safe e reutilizáveis. Eles convertem objetos que implementam a interface selada &lt;code&gt;BinaryEncodable&lt;/code&gt;: chaves assimétricas, &lt;code&gt;KeyPair&lt;/code&gt;, &lt;code&gt;X509Certificate&lt;/code&gt;, &lt;code&gt;X509CRL&lt;/code&gt;, &lt;code&gt;EncryptedPrivateKeyInfo&lt;/code&gt;, as key specs PKCS#8 e X.509 e a classe genérica &lt;code&gt;PEM&lt;/code&gt;, que cobre tipos sem API própria, como requisições de certificado PKCS#10.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;ChavesPem.java&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; java.security.KeyPair;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; java.security.KeyPairGenerator;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; java.security.PEMDecoder;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; java.security.PEMEncoder;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; java.security.PrivateKey;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; java.security.PublicKey;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; java.security.interfaces.ECPrivateKey;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; java.security.interfaces.ECPublicKey;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;ChavesPem&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;main&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;[] &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;args&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;throws&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; Exception {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;KeyPair par &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; KeyPairGenerator.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;getInstance&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;EC&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;generateKeyPair&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;char&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;[] senha &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;troque-esta-senha&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;toCharArray&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// Codificação: encoders são imutáveis e reutilizáveis&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;PEMEncoder encoder &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; PEMEncoder.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;String publicaPem &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; encoder.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;encodeToString&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(par.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;getPublic&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;());&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;String privadaPem &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; encoder.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;withEncryption&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(senha).&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;encodeToString&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(par.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;getPrivate&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;());&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;IO.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(publicaPem.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;lines&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;findFirst&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;orElseThrow&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;()); &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// -----BEGIN PUBLIC KEY-----&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;IO.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(privadaPem.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;lines&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;findFirst&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;orElseThrow&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;()); &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// -----BEGIN ENCRYPTED PRIVATE KEY-----&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// Decodificação com o tipo esperado&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;PEMDecoder decoder &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; PEMDecoder.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;ECPublicKey publica &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; decoder.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;decode&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(publicaPem, ECPublicKey.class);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;ECPrivateKey privada &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; decoder.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;withDecryption&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(senha).&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;decode&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(privadaPem, ECPrivateKey.class);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;IO.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(publica.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;getAlgorithm&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot; / &quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; privada.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;getAlgorithm&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;()); &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// EC / EC&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// Ou sem saber o tipo de antemão, com pattern matching&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;switch&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (decoder.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;decode&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(publicaPem)) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;case&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; PublicKey pk &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; IO.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;chave pública &quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; pk.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;getFormat&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;()); &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// chave pública X.509&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;case&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; PrivateKey sk &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; IO.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;chave privada&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; IO.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;outro objeto PEM&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Para rodar: &lt;code&gt;java --enable-preview --source 27 ChavesPem.java&lt;/code&gt;. O código é o mesmo no Java 26, onde a interface ainda se chamava &lt;code&gt;DEREncodable&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;O &lt;code&gt;default&lt;/code&gt; é obrigatório no &lt;code&gt;switch&lt;/code&gt; porque o &lt;code&gt;decode&lt;/code&gt; pode devolver outros tipos, como &lt;code&gt;KeyPair&lt;/code&gt;, &lt;code&gt;X509Certificate&lt;/code&gt; ou &lt;code&gt;PEM&lt;/code&gt;. Mesmo um &lt;code&gt;switch&lt;/code&gt; que liste todos os tipos públicos precisaria dele: a lista de subtipos de &lt;code&gt;BinaryEncodable&lt;/code&gt; não é exaustiva, o que, segundo o &lt;a href=&quot;https://github.com/openjdk/jdk/blob/jdk-27-ga/src/java.base/share/classes/java/security/BinaryEncodable.java&quot;&gt;Javadoc de &lt;code&gt;BinaryEncodable&lt;/code&gt;&lt;/a&gt;, permite ampliá-la no futuro sem quebrar código existente.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;O que mudou no caminho.&lt;/strong&gt; No Java 26, &lt;code&gt;PEMRecord&lt;/code&gt; virou &lt;code&gt;PEM&lt;/code&gt;, os métodos &lt;code&gt;encryptKey&lt;/code&gt; de &lt;code&gt;EncryptedPrivateKeyInfo&lt;/code&gt; viraram &lt;code&gt;encrypt&lt;/code&gt;, e encoder e decoder passaram a cifrar e decifrar &lt;code&gt;KeyPair&lt;/code&gt; e &lt;code&gt;PKCS8EncodedKeySpec&lt;/code&gt;. No Java 27, &lt;code&gt;DEREncodable&lt;/code&gt; virou &lt;code&gt;BinaryEncodable&lt;/code&gt;, &lt;code&gt;PEM&lt;/code&gt; deixou de ser record e virou classe comum, &lt;code&gt;PEMDecoder.withFactory&lt;/code&gt; virou &lt;code&gt;withFactoriesOf&lt;/code&gt;, e entrou a exceção não verificada &lt;code&gt;javax.crypto.CryptoException&lt;/code&gt;. A &lt;a href=&quot;https://openjdk.org/jeps/542&quot;&gt;JEP 542&lt;/a&gt;, já concluída para o Java 28, finaliza a API &lt;strong&gt;sem outras mudanças&lt;/strong&gt;. Ou seja: o código escrito para o 27 deve funcionar no 28 sem &lt;code&gt;--enable-preview&lt;/code&gt;, e é a partir dali que vale trocar o parsing manual de PEM pela API em código de produção.&lt;/p&gt;
&lt;h3 id=&quot;vector-api&quot;&gt;Vector API&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#vector-api&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Chegou em:&lt;/strong&gt; Java 25 (10ª incubadora, &lt;a href=&quot;https://openjdk.org/jeps/508&quot;&gt;JEP 508&lt;/a&gt;) → Java 26 (11ª incubadora, &lt;a href=&quot;https://openjdk.org/jeps/529&quot;&gt;JEP 529&lt;/a&gt;) → Java 27 (12ª incubadora, &lt;a href=&quot;https://openjdk.org/jeps/537&quot;&gt;JEP 537&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;A Vector API (veja &lt;a href=&quot;https://cesarschutz.com.br/posts/java-25/#vector-api&quot;&gt;Vector API no post do Java 25&lt;/a&gt;) expressa cálculos vetoriais que o JIT compila para instruções SIMD da CPU, que aplicam a mesma operação a vários valores de uma vez. Nas duas versões ela voltou sem mudança relevante de API; no 27, só a biblioteca SLEEF usada em ARM e RISC-V foi atualizada. Pelas JEPs, ela fica na incubadora até que os recursos necessários do Project Valhalla cheguem como preview. Em 16/09/2026, o primeiro preview de Value Objects (&lt;a href=&quot;https://openjdk.org/jeps/401&quot;&gt;JEP 401&lt;/a&gt;), do Valhalla, já tinha alvo no Java 28.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;SomaVetorial.java&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; jdk.incubator.vector.FloatVector;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; jdk.incubator.vector.VectorSpecies;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;SomaVetorial&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;final&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; VectorSpecies&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;Float&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&gt; ESPECIE &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; FloatVector.SPECIES_PREFERRED;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// c[i] = -(a[i]² + b[i]²), processando várias posições por instrução da CPU&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;calcular&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;float&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;[] &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;float&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;[] &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;b&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;float&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;[] &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;c&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; i &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; limite &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; ESPECIE.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;loopBound&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(a.length);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (; i &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; limite; i &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;+=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; ESPECIE.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;length&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;()) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; va &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; FloatVector.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;fromArray&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(ESPECIE, a, i);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; vb &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; FloatVector.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;fromArray&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(ESPECIE, b, i);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;va.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;mul&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(va).&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(vb.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;mul&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(vb)).&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;neg&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;intoArray&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(c, i);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (; i &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; a.length; i&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) {           &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// sobra que não completa um vetor&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;c[i] &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (a[i] &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; a[i] &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; b[i] &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; b[i]) &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;1.0f&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;main&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;[] &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;args&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;float&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;[] a &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;6&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;7&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;8&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;9&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;float&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;[] b &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;9&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;8&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;7&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;6&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;float&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;[] c &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;float&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;[a.length];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;calcular&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(a, b, c);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;IO.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(java.util.Arrays.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;toString&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(c));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// [-82.0, -68.0, -58.0, -52.0, -50.0, -52.0, -58.0, -68.0, -82.0]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Para rodar: &lt;code&gt;java --add-modules jdk.incubator.vector SomaVetorial.java&lt;/code&gt;. Sem o &lt;code&gt;--add-modules&lt;/code&gt;, o pacote não fica visível e a compilação falha. Com ele, a JVM também imprime &lt;code&gt;WARNING: Using incubator modules: jdk.incubator.vector&lt;/code&gt; antes da saída.&lt;/p&gt;
&lt;h2 id=&quot;o-que-observar-vindo-do-java-25&quot;&gt;O que observar vindo do Java 25&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#o-que-observar-vindo-do-java-25&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Mudanças confirmadas no 26 e no 27 que podem quebrar build, testes ou comportamento em produção:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Recompilar tudo o que usa preview.&lt;/strong&gt; Pela &lt;a href=&quot;https://openjdk.org/jeps/12&quot;&gt;JEP 12&lt;/a&gt;, uma JVM não carrega classes que dependem dos previews de outra versão. E as APIs mudaram entre versões: exceções do &lt;a href=&quot;#structured-concurrency&quot;&gt;&lt;code&gt;StructuredTaskScope&lt;/code&gt;&lt;/a&gt; (&lt;code&gt;FailedException&lt;/code&gt; → &lt;code&gt;ExecutionException&lt;/code&gt;), &lt;a href=&quot;#lazy-constants&quot;&gt;&lt;code&gt;StableValue&lt;/code&gt; → &lt;code&gt;LazyConstant&lt;/code&gt;&lt;/a&gt; sem &lt;code&gt;isInitialized&lt;/code&gt;/&lt;code&gt;orElse&lt;/code&gt;, &lt;a href=&quot;#api-pem&quot;&gt;&lt;code&gt;DEREncodable&lt;/code&gt; → &lt;code&gt;BinaryEncodable&lt;/code&gt;&lt;/a&gt;. Com a &lt;a href=&quot;#tipos-primitivos-em-patterns-instanceof-e-switch&quot;&gt;dominância mais rígida&lt;/a&gt; em &lt;code&gt;switch&lt;/code&gt; com primitivos, alguns &lt;code&gt;switch&lt;/code&gt; que compilavam deixam de compilar.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Avisos de &lt;code&gt;final&lt;/code&gt; alterado por reflexão&lt;/strong&gt; (&lt;a href=&quot;https://openjdk.org/jeps/500&quot;&gt;JEP 500&lt;/a&gt;, &lt;a href=&quot;#muta%C3%A7%C3%A3o-de-campos-final-por-reflex%C3%A3o-passa-a-emitir-aviso&quot;&gt;detalhes&lt;/a&gt;). Procure os &lt;code&gt;WARNING: Final field ...&lt;/code&gt; nos logs e rode os testes com &lt;code&gt;--illegal-final-field-mutation=deny&lt;/code&gt;. Frameworks de injeção, mocks e serialização são os suspeitos de sempre.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Coletor em containers pequenos&lt;/strong&gt; (&lt;a href=&quot;https://openjdk.org/jeps/523&quot;&gt;JEP 523&lt;/a&gt;, &lt;a href=&quot;#g1-como-coletor-padr%C3%A3o-em-qualquer-ambiente&quot;&gt;detalhes&lt;/a&gt;). Com 1 CPU ou menos de 1792 MB, o padrão passa de Serial para G1. Meça memória e latência e, se preciso, fixe &lt;code&gt;-XX:+UseSerialGC&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Layout de objeto&lt;/strong&gt; (&lt;a href=&quot;https://openjdk.org/jeps/534&quot;&gt;JEP 534&lt;/a&gt;, &lt;a href=&quot;#compact-object-headers-ligados-por-padr%C3%A3o&quot;&gt;detalhes&lt;/a&gt;). Os compact object headers vêm ligados. Se algo depender do layout antigo, &lt;code&gt;-XX:-UseCompactObjectHeaders&lt;/code&gt; desliga.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Flags e dimensionamento de heap.&lt;/strong&gt; No 26, sem &lt;code&gt;-Xms&lt;/code&gt;, o heap inicial passa a ser o mínimo possível; quem dependia do padrão antigo pode fixar &lt;code&gt;-Xms&lt;/code&gt; ou &lt;code&gt;-XX:InitialRAMPercentage=1.5625&lt;/code&gt; (&lt;a href=&quot;https://www.oracle.com/java/technologies/javase/26-relnote-issues.html&quot;&gt;notas do 26&lt;/a&gt;). No 27, &lt;code&gt;-noverify&lt;/code&gt;/&lt;code&gt;-Xverify:none&lt;/code&gt;, &lt;code&gt;-noclassgc&lt;/code&gt;, &lt;code&gt;-verifyremote&lt;/code&gt; e &lt;code&gt;-XX:+UseGraalJIT&lt;/code&gt; foram removidas, &lt;code&gt;UseCompressedClassPointers&lt;/code&gt; ficou obsoleta, os padrões de &lt;code&gt;Min/MaxHeapFreeRatio&lt;/code&gt; no G1 mudaram e &lt;code&gt;InitiatingHeapOccupancyPercent&lt;/code&gt; virou &lt;code&gt;G1IHOP&lt;/code&gt; (&lt;a href=&quot;https://jdk.java.net/27/release-notes&quot;&gt;notas do 27&lt;/a&gt;). Revise scripts de startup, Dockerfiles e &lt;code&gt;JAVA_TOOL_OPTIONS&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;APIs removidas.&lt;/strong&gt; &lt;code&gt;Thread.stop()&lt;/code&gt;, a Applet API e &lt;code&gt;ThreadPoolExecutor.finalize()&lt;/code&gt;. No último caso, quem sobrescrevia &lt;code&gt;finalize()&lt;/code&gt; chamando &lt;code&gt;super.finalize()&lt;/code&gt; passa a chamar &lt;code&gt;Object.finalize()&lt;/code&gt;, que declara &lt;code&gt;throws Throwable&lt;/code&gt;, e o código pode deixar de compilar (&lt;a href=&quot;https://jdk.java.net/27/release-notes&quot;&gt;notas do 27&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rede e HTTP.&lt;/strong&gt; No 26, o timeout de &lt;code&gt;HttpRequest.Builder.timeout&lt;/code&gt; passou a cobrir também a leitura do corpo da resposta, e os atributos de &lt;code&gt;HttpContext&lt;/code&gt; deixaram de ser compartilhados com cada &lt;code&gt;HttpExchange&lt;/code&gt; no servidor embutido (a propriedade &lt;code&gt;jdk.httpserver.attributes&lt;/code&gt; restaura o comportamento antigo). No 27, o &lt;code&gt;HttpServer&lt;/code&gt; passou de casamento por prefixo de string para prefixo de caminho: o contexto &lt;code&gt;/foo&lt;/code&gt; não casa mais com &lt;code&gt;/foobar&lt;/code&gt;, e a propriedade &lt;code&gt;sun.net.httpserver.pathMatcher&lt;/code&gt; restaura o comportamento antigo (&lt;a href=&quot;https://www.oracle.com/java/technologies/javase/26-relnote-issues.html&quot;&gt;notas do 26&lt;/a&gt;, &lt;a href=&quot;https://jdk.java.net/27/release-notes&quot;&gt;notas do 27&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;TLS e criptografia no 27.&lt;/strong&gt; &lt;code&gt;X25519MLKEM768&lt;/code&gt; vira o grupo preferido. &lt;code&gt;ffdhe6144&lt;/code&gt;/&lt;code&gt;ffdhe8192&lt;/code&gt; saem da lista padrão. A derivação de chave do TLS 1.3 passa a usar chaves &lt;code&gt;Generic&lt;/code&gt;, e providers JCE que não as suportam podem falhar no handshake (a propriedade &lt;code&gt;jdk.tls.t13KeyDerivationAlgorithm=TlsPremasterSecret&lt;/code&gt; restaura o comportamento anterior). Chaves privadas ML-KEM e ML-DSA codificadas no 27 (formato &lt;code&gt;seed&lt;/code&gt;) não são aceitas por versões anteriores por padrão (&lt;a href=&quot;https://jdk.java.net/27/release-notes&quot;&gt;notas do 27&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Saídas e exceções que mudaram.&lt;/strong&gt; No 26, &lt;code&gt;DecimalFormat&lt;/code&gt; passou a usar o algoritmo de &lt;code&gt;Double.toString&lt;/code&gt; (&lt;code&gt;-Djdk.compat.DecimalFormat=true&lt;/code&gt; restaura o antigo). No 27, o thread dump em JSON usa números nos IDs, e &lt;code&gt;ZipOutputStream.putNextEntry&lt;/code&gt; lança &lt;code&gt;ZipException&lt;/code&gt; em vez de &lt;code&gt;IllegalArgumentException&lt;/code&gt; para nomes que não podem ser codificados (&lt;a href=&quot;https://www.oracle.com/java/technologies/javase/26-relnote-issues.html&quot;&gt;notas do 26&lt;/a&gt;, &lt;a href=&quot;https://jdk.java.net/27/release-notes&quot;&gt;notas do 27&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dados de locale, TLS e compilação.&lt;/strong&gt; No 26, os dados de locale passaram ao CLDR 48 e, no 27, ao CLDR 48.2, com mudanças em formatos de data, hora e número (por exemplo, o separador de milhar suíço); testes que comparam texto formatado podem falhar. Também no 26, conexões RMI sobre TLS passaram a verificar por padrão se o certificado do servidor corresponde ao nome do host (&lt;code&gt;jdk.rmi.ssl.client.enableEndpointIdentification=false&lt;/code&gt; desliga), e o &lt;code&gt;KeyManager&lt;/code&gt; &lt;code&gt;SunX509&lt;/code&gt; passou a checar os certificados locais contra as restrições de algoritmos (&lt;code&gt;jdk.tls.SunX509KeyManager.certChecking=false&lt;/code&gt; restaura o comportamento antigo). No 27, o &lt;code&gt;javac&lt;/code&gt; passou a rejeitar anotações &lt;code&gt;TYPE_USE&lt;/code&gt; em variáveis com tipo inferido, como as declaradas com &lt;code&gt;var&lt;/code&gt;, inclusive parâmetros de lambda (&lt;a href=&quot;https://www.oracle.com/java/technologies/javase/26-relnote-issues.html&quot;&gt;notas do 26&lt;/a&gt;, &lt;a href=&quot;https://jdk.java.net/27/release-notes&quot;&gt;notas do 27&lt;/a&gt;).&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;todas-as-jeps-versão-a-versão&quot;&gt;Todas as JEPs, versão a versão&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#todas-as-jeps-versão-a-versão&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Listas conferidas nas páginas oficiais de cada release no OpenJDK; os títulos seguem as páginas das JEPs. Tipos: &lt;strong&gt;Final&lt;/strong&gt; (recurso permanente ou mudança de implementação), &lt;strong&gt;Preview&lt;/strong&gt;, &lt;strong&gt;Incubadora&lt;/strong&gt;, &lt;strong&gt;Experimental&lt;/strong&gt;, &lt;strong&gt;Depreciação&lt;/strong&gt;, &lt;strong&gt;Remoção&lt;/strong&gt;, &lt;strong&gt;Plataforma&lt;/strong&gt; (port para sistema operacional ou arquitetura) e &lt;strong&gt;Interno&lt;/strong&gt; (mudança no desenvolvimento do próprio OpenJDK, sem efeito para quem usa o JDK).&lt;/p&gt;
&lt;h3 id=&quot;java-26&quot;&gt;Java 26&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#java-26&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Lançado em 17 de março de 2026, com 10 JEPs (&lt;a href=&quot;https://openjdk.org/projects/jdk/26/&quot;&gt;JDK 26&lt;/a&gt;).&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;Ver as 10 JEPs do Java 26&lt;/summary&gt;
&lt;div class=&quot;table-wrap&quot;&gt;



























































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;JEP&lt;/th&gt;&lt;th&gt;Título&lt;/th&gt;&lt;th&gt;Tipo&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://openjdk.org/jeps/500&quot;&gt;500&lt;/a&gt;&lt;/td&gt;&lt;td&gt;Prepare to Make Final Mean Final&lt;/td&gt;&lt;td&gt;Final&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://openjdk.org/jeps/504&quot;&gt;504&lt;/a&gt;&lt;/td&gt;&lt;td&gt;Remove the Applet API&lt;/td&gt;&lt;td&gt;Remoção&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://openjdk.org/jeps/516&quot;&gt;516&lt;/a&gt;&lt;/td&gt;&lt;td&gt;Ahead-of-Time Object Caching with Any GC&lt;/td&gt;&lt;td&gt;Final&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://openjdk.org/jeps/517&quot;&gt;517&lt;/a&gt;&lt;/td&gt;&lt;td&gt;HTTP/3 for the HTTP Client API&lt;/td&gt;&lt;td&gt;Final&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://openjdk.org/jeps/522&quot;&gt;522&lt;/a&gt;&lt;/td&gt;&lt;td&gt;G1 GC: Improve Throughput by Reducing Synchronization&lt;/td&gt;&lt;td&gt;Final&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://openjdk.org/jeps/524&quot;&gt;524&lt;/a&gt;&lt;/td&gt;&lt;td&gt;PEM Encodings of Cryptographic Objects (Second Preview)&lt;/td&gt;&lt;td&gt;Preview&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://openjdk.org/jeps/525&quot;&gt;525&lt;/a&gt;&lt;/td&gt;&lt;td&gt;Structured Concurrency (Sixth Preview)&lt;/td&gt;&lt;td&gt;Preview&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://openjdk.org/jeps/526&quot;&gt;526&lt;/a&gt;&lt;/td&gt;&lt;td&gt;Lazy Constants (Second Preview)&lt;/td&gt;&lt;td&gt;Preview&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://openjdk.org/jeps/529&quot;&gt;529&lt;/a&gt;&lt;/td&gt;&lt;td&gt;Vector API (Eleventh Incubator)&lt;/td&gt;&lt;td&gt;Incubadora&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://openjdk.org/jeps/530&quot;&gt;530&lt;/a&gt;&lt;/td&gt;&lt;td&gt;Primitive Types in Patterns, instanceof, and switch (Fourth Preview)&lt;/td&gt;&lt;td&gt;Preview&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;
&lt;/details&gt;
&lt;h3 id=&quot;java-27&quot;&gt;Java 27&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#java-27&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Lançado em 15 de setembro de 2026, com 9 JEPs (&lt;a href=&quot;https://openjdk.org/projects/jdk/27/&quot;&gt;JDK 27&lt;/a&gt;).&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;Ver as 9 JEPs do Java 27&lt;/summary&gt;
&lt;div class=&quot;table-wrap&quot;&gt;






















































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;JEP&lt;/th&gt;&lt;th&gt;Título&lt;/th&gt;&lt;th&gt;Tipo&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://openjdk.org/jeps/523&quot;&gt;523&lt;/a&gt;&lt;/td&gt;&lt;td&gt;Make G1 the Default Garbage Collector in All Environments&lt;/td&gt;&lt;td&gt;Final&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://openjdk.org/jeps/527&quot;&gt;527&lt;/a&gt;&lt;/td&gt;&lt;td&gt;Post-Quantum Hybrid Key Exchange for TLS 1.3&lt;/td&gt;&lt;td&gt;Final&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://openjdk.org/jeps/531&quot;&gt;531&lt;/a&gt;&lt;/td&gt;&lt;td&gt;Lazy Constants (Third Preview)&lt;/td&gt;&lt;td&gt;Preview&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://openjdk.org/jeps/532&quot;&gt;532&lt;/a&gt;&lt;/td&gt;&lt;td&gt;Primitive Types in Patterns, instanceof, and switch (Fifth Preview)&lt;/td&gt;&lt;td&gt;Preview&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://openjdk.org/jeps/533&quot;&gt;533&lt;/a&gt;&lt;/td&gt;&lt;td&gt;Structured Concurrency (Seventh Preview)&lt;/td&gt;&lt;td&gt;Preview&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://openjdk.org/jeps/534&quot;&gt;534&lt;/a&gt;&lt;/td&gt;&lt;td&gt;Compact Object Headers by Default&lt;/td&gt;&lt;td&gt;Final&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://openjdk.org/jeps/536&quot;&gt;536&lt;/a&gt;&lt;/td&gt;&lt;td&gt;JFR In-Process Data Redaction&lt;/td&gt;&lt;td&gt;Final&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://openjdk.org/jeps/537&quot;&gt;537&lt;/a&gt;&lt;/td&gt;&lt;td&gt;Vector API (Twelfth Incubator)&lt;/td&gt;&lt;td&gt;Incubadora&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://openjdk.org/jeps/538&quot;&gt;538&lt;/a&gt;&lt;/td&gt;&lt;td&gt;PEM Encodings of Cryptographic Objects (Third Preview)&lt;/td&gt;&lt;td&gt;Preview&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;
&lt;/details&gt;
&lt;h3 id=&quot;java-28&quot;&gt;Java 28&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#java-28&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Em desenvolvimento. A &lt;a href=&quot;https://openjdk.org/projects/jdk/28/&quot;&gt;página do JDK 28&lt;/a&gt; ainda não publicou o cronograma, e o roadmap da Oracle prevê o lançamento para março de 2027. Na última atualização da página (27/08/2026), estas eram as JEPs com alvo no 28; a coluna Situação mostra o status de cada JEP em 16/09/2026. “Com alvo” significa que a JEP foi aceita para o 28; “integrada”, que o código já entrou no repositório do 28; “concluída”, que além disso a JEP foi encerrada como entregue.&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;Ver as 6 JEPs do Java 28&lt;/summary&gt;
&lt;div class=&quot;table-wrap&quot;&gt;














































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;JEP&lt;/th&gt;&lt;th&gt;Título&lt;/th&gt;&lt;th&gt;Tipo&lt;/th&gt;&lt;th&gt;Situação&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://openjdk.org/jeps/401&quot;&gt;401&lt;/a&gt;&lt;/td&gt;&lt;td&gt;Value Objects (Preview)&lt;/td&gt;&lt;td&gt;Preview&lt;/td&gt;&lt;td&gt;Integrada ao 28&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://openjdk.org/jeps/535&quot;&gt;535&lt;/a&gt;&lt;/td&gt;&lt;td&gt;Shenandoah GC: Generational Mode by Default&lt;/td&gt;&lt;td&gt;Final&lt;/td&gt;&lt;td&gt;Com alvo no 28, ainda não integrada&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://openjdk.org/jeps/539&quot;&gt;539&lt;/a&gt;&lt;/td&gt;&lt;td&gt;Strict Field Initialization in the JVM (Preview)&lt;/td&gt;&lt;td&gt;Preview&lt;/td&gt;&lt;td&gt;Integrada ao 28&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://openjdk.org/jeps/540&quot;&gt;540&lt;/a&gt;&lt;/td&gt;&lt;td&gt;Simple JSON API (Incubator)&lt;/td&gt;&lt;td&gt;Incubadora&lt;/td&gt;&lt;td&gt;Integrada ao 28&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://openjdk.org/jeps/541&quot;&gt;541&lt;/a&gt;&lt;/td&gt;&lt;td&gt;Deprecate the macOS/x64 Port for Removal&lt;/td&gt;&lt;td&gt;Depreciação&lt;/td&gt;&lt;td&gt;Concluída no 28&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://openjdk.org/jeps/542&quot;&gt;542&lt;/a&gt;&lt;/td&gt;&lt;td&gt;PEM Encodings of Cryptographic Objects&lt;/td&gt;&lt;td&gt;Final&lt;/td&gt;&lt;td&gt;Concluída no 28&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;
&lt;/details&gt;
&lt;p&gt;Em resumo: &lt;strong&gt;Value Objects&lt;/strong&gt; (Project Valhalla) introduz, em preview, objetos imutáveis e sem identidade, distinguidos só pelos valores dos campos, que a JVM pode representar de forma mais eficiente. &lt;strong&gt;Strict Field Initialization&lt;/strong&gt; é um recurso de VM em preview, voltado a compiladores que geram class files, no qual o campo precisa ser inicializado antes de qualquer leitura, de modo que &lt;code&gt;0&lt;/code&gt; e &lt;code&gt;null&lt;/code&gt; nunca são observados. A &lt;strong&gt;Simple JSON API&lt;/strong&gt; (&lt;code&gt;jdk.incubator.json&lt;/code&gt;) faz parsing e geração de JSON sem biblioteca externa. No &lt;strong&gt;Shenandoah&lt;/strong&gt;, o modo geracional vira padrão e o não geracional (&lt;code&gt;ShenandoahGCMode=satb&lt;/code&gt;) é depreciado. A &lt;strong&gt;API PEM&lt;/strong&gt; vira final.&lt;/p&gt;
&lt;p&gt;Fora da lista, a &lt;a href=&quot;https://openjdk.org/jeps/543&quot;&gt;JEP 543&lt;/a&gt; (candidata, sem versão definida) propõe finalizar Structured Concurrency no Java 28. Nada disso está garantido até o Java 28 sair, e este post será atualizado quando isso acontecer.&lt;/p&gt;
&lt;h2 id=&quot;fontes&quot;&gt;Fontes&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#fontes&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Consultadas em 16/09/2026.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cronograma e suporte&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.oracle.com/java/technologies/java-se-support-roadmap.html&quot;&gt;Oracle Java SE Support Roadmap&lt;/a&gt;: Java 29 como próxima LTS prevista (setembro de 2027); 26, 27 e 28 não LTS; prazos de Premier Support&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://openjdk.org/projects/jdk/26/&quot;&gt;JDK 26, página do projeto&lt;/a&gt;: JEPs e GA em 17/03/2026&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://openjdk.org/projects/jdk/27/&quot;&gt;JDK 27, página do projeto&lt;/a&gt;: JEPs, cronograma e GA em 15/09/2026&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://openjdk.org/projects/jdk/28/&quot;&gt;JDK 28, página do projeto&lt;/a&gt;: JEPs com alvo no 28&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://openjdk.org/jeps/0&quot;&gt;JEP 0 — JEP Index&lt;/a&gt;: status das JEPs em andamento&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://mail.openjdk.org/archives/list/announce@openjdk.org/thread/ORGGLMN75HFEWP7YL3ZLGHLYHVIBJDYT/&quot;&gt;Anúncio de GA do JDK 27 (announce@openjdk.org)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://mail.openjdk.org/archives/list/jdk-dev@openjdk.org/thread/2MXXXBJKTJXQD25Q4XGGINKYA33T7D5I/&quot;&gt;Anúncio de GA do JDK 26 (jdk-dev@openjdk.org)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Notas de release&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://jdk.java.net/27/release-notes&quot;&gt;JDK 27 Release Notes (jdk.java.net)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.oracle.com/java/technologies/javase/26-relnote-issues.html&quot;&gt;JDK 26 Release Notes (Oracle)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://bugs.openjdk.org/browse/JDK-8369238&quot;&gt;JDK-8369238&lt;/a&gt;: virtual threads e inicialização de classes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;JEPs&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Anteriores ao Java 26: &lt;a href=&quot;https://openjdk.org/jeps/243&quot;&gt;JEP 243&lt;/a&gt;, &lt;a href=&quot;https://openjdk.org/jeps/248&quot;&gt;JEP 248&lt;/a&gt;, &lt;a href=&quot;https://openjdk.org/jeps/289&quot;&gt;JEP 289&lt;/a&gt;, &lt;a href=&quot;https://openjdk.org/jeps/321&quot;&gt;JEP 321&lt;/a&gt;, &lt;a href=&quot;https://openjdk.org/jeps/398&quot;&gt;JEP 398&lt;/a&gt;, &lt;a href=&quot;https://openjdk.org/jeps/450&quot;&gt;JEP 450&lt;/a&gt;, &lt;a href=&quot;https://openjdk.org/jeps/483&quot;&gt;JEP 483&lt;/a&gt;, &lt;a href=&quot;https://openjdk.org/jeps/470&quot;&gt;JEP 470&lt;/a&gt;, &lt;a href=&quot;https://openjdk.org/jeps/502&quot;&gt;JEP 502&lt;/a&gt;, &lt;a href=&quot;https://openjdk.org/jeps/505&quot;&gt;JEP 505&lt;/a&gt;, &lt;a href=&quot;https://openjdk.org/jeps/507&quot;&gt;JEP 507&lt;/a&gt;, &lt;a href=&quot;https://openjdk.org/jeps/508&quot;&gt;JEP 508&lt;/a&gt;, &lt;a href=&quot;https://openjdk.org/jeps/514&quot;&gt;JEP 514&lt;/a&gt;, &lt;a href=&quot;https://openjdk.org/jeps/519&quot;&gt;JEP 519&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Java 26: &lt;a href=&quot;https://openjdk.org/jeps/500&quot;&gt;JEP 500&lt;/a&gt;, &lt;a href=&quot;https://openjdk.org/jeps/504&quot;&gt;JEP 504&lt;/a&gt;, &lt;a href=&quot;https://openjdk.org/jeps/516&quot;&gt;JEP 516&lt;/a&gt;, &lt;a href=&quot;https://openjdk.org/jeps/517&quot;&gt;JEP 517&lt;/a&gt;, &lt;a href=&quot;https://openjdk.org/jeps/522&quot;&gt;JEP 522&lt;/a&gt;, &lt;a href=&quot;https://openjdk.org/jeps/524&quot;&gt;JEP 524&lt;/a&gt;, &lt;a href=&quot;https://openjdk.org/jeps/525&quot;&gt;JEP 525&lt;/a&gt;, &lt;a href=&quot;https://openjdk.org/jeps/526&quot;&gt;JEP 526&lt;/a&gt;, &lt;a href=&quot;https://openjdk.org/jeps/529&quot;&gt;JEP 529&lt;/a&gt;, &lt;a href=&quot;https://openjdk.org/jeps/530&quot;&gt;JEP 530&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Java 27: &lt;a href=&quot;https://openjdk.org/jeps/523&quot;&gt;JEP 523&lt;/a&gt;, &lt;a href=&quot;https://openjdk.org/jeps/527&quot;&gt;JEP 527&lt;/a&gt;, &lt;a href=&quot;https://openjdk.org/jeps/531&quot;&gt;JEP 531&lt;/a&gt;, &lt;a href=&quot;https://openjdk.org/jeps/532&quot;&gt;JEP 532&lt;/a&gt;, &lt;a href=&quot;https://openjdk.org/jeps/533&quot;&gt;JEP 533&lt;/a&gt;, &lt;a href=&quot;https://openjdk.org/jeps/534&quot;&gt;JEP 534&lt;/a&gt;, &lt;a href=&quot;https://openjdk.org/jeps/536&quot;&gt;JEP 536&lt;/a&gt;, &lt;a href=&quot;https://openjdk.org/jeps/537&quot;&gt;JEP 537&lt;/a&gt;, &lt;a href=&quot;https://openjdk.org/jeps/538&quot;&gt;JEP 538&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Java 28 (com alvo ou candidata): &lt;a href=&quot;https://openjdk.org/jeps/401&quot;&gt;JEP 401&lt;/a&gt;, &lt;a href=&quot;https://openjdk.org/jeps/535&quot;&gt;JEP 535&lt;/a&gt;, &lt;a href=&quot;https://openjdk.org/jeps/539&quot;&gt;JEP 539&lt;/a&gt;, &lt;a href=&quot;https://openjdk.org/jeps/540&quot;&gt;JEP 540&lt;/a&gt;, &lt;a href=&quot;https://openjdk.org/jeps/541&quot;&gt;JEP 541&lt;/a&gt;, &lt;a href=&quot;https://openjdk.org/jeps/542&quot;&gt;JEP 542&lt;/a&gt;, &lt;a href=&quot;https://openjdk.org/jeps/543&quot;&gt;JEP 543&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Processo: &lt;a href=&quot;https://openjdk.org/jeps/11&quot;&gt;JEP 11 — Incubator Modules&lt;/a&gt; e &lt;a href=&quot;https://openjdk.org/jeps/12&quot;&gt;JEP 12 — Preview Features&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Código-fonte do JDK 27 (tag &lt;code&gt;jdk-27-ga&lt;/code&gt;)&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/openjdk/jdk/blob/jdk-27-ga/src/java.base/share/classes/java/util/concurrent/StructuredTaskScope.java&quot;&gt;StructuredTaskScope.java&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/openjdk/jdk/blob/jdk-27-ga/src/java.base/share/classes/java/lang/LazyConstant.java&quot;&gt;LazyConstant.java&lt;/a&gt; e &lt;a href=&quot;https://github.com/openjdk/jdk/blob/jdk-27-ga/src/java.base/share/classes/java/util/Set.java&quot;&gt;Set.java (&lt;code&gt;Set.ofLazy&lt;/code&gt;)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/openjdk/jdk/blob/jdk-27-ga/src/java.base/share/classes/java/security/PEMEncoder.java&quot;&gt;PEMEncoder.java&lt;/a&gt;, &lt;a href=&quot;https://github.com/openjdk/jdk/blob/jdk-27-ga/src/java.base/share/classes/java/security/PEMDecoder.java&quot;&gt;PEMDecoder.java&lt;/a&gt;, &lt;a href=&quot;https://github.com/openjdk/jdk/blob/jdk-27-ga/src/java.base/share/classes/java/security/BinaryEncodable.java&quot;&gt;BinaryEncodable.java&lt;/a&gt; e &lt;a href=&quot;https://github.com/openjdk/jdk/blob/jdk-27-ga/src/java.base/share/classes/javax/crypto/CryptoException.java&quot;&gt;CryptoException.java&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/openjdk/jdk/blob/jdk-27-ga/src/java.net.http/share/classes/java/net/http/HttpOption.java&quot;&gt;HttpOption.java&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>Atualizações do Java</category><category>LTS</category><category>JVM</category><category>Concorrência</category><category>Criptografia</category></item><item><title>Bloqueio otimista e pessimista — como funcionam e quando usar cada um</title><link>https://cesarschutz.com.br/posts/bloqueio-otimista-e-pessimista/</link><guid isPermaLink="true">https://cesarschutz.com.br/posts/bloqueio-otimista-e-pessimista/</guid><description>Como impedir que gravações simultâneas se atropelem: coluna de versão ou trava da linha. SQL testado no PostgreSQL, Spring Data JPA, FOR UPDATE com NOWAIT e SKIP LOCKED, deadlocks e isolamento.</description><pubDate>Sun, 13 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Quando duas requisições leem a mesma linha, calculam um valor novo e gravam, uma delas pode apagar o trabalho da outra sem erro nenhum. Este post mostra as duas formas clássicas de impedir isso, o &lt;strong&gt;bloqueio otimista&lt;/strong&gt; (detectar o conflito) e o &lt;strong&gt;bloqueio pessimista&lt;/strong&gt; (evitar o conflito), com SQL testado no PostgreSQL 17 e o equivalente em Spring Data JPA. No fim, há um critério para escolher entre os dois e um terceiro caminho que muitas vezes dispensa ambos: o UPDATE condicional.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;O tema aparece de raspão no artigo sobre &lt;a href=&quot;https://cesarschutz.com.br/posts/cobranca-duplicada-no-retry/&quot;&gt;cobrança duplicada no retry&lt;/a&gt;, como alternativa à restrição única. Aqui ele ganha o espaço que merece.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;1-o-problema-que-os-dois-resolvem&quot;&gt;1. O problema que os dois resolvem&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#1-o-problema-que-os-dois-resolvem&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Os dois existem para o mesmo defeito, que tem nome: &lt;strong&gt;lost update&lt;/strong&gt;, a atualização perdida.&lt;/p&gt;
&lt;p&gt;Dois clientes leem a mesma linha, cada um calcula um valor novo a partir do que leu, e os dois gravam. A segunda gravação sobrescreve a primeira, e a primeira desaparece sem erro nenhum. O saldo fica errado e o log está limpo.&lt;/p&gt;
&lt;p&gt;É a mesma família do problema de &lt;a href=&quot;https://cesarschutz.com.br/posts/cobranca-duplicada-no-retry/&quot;&gt;cobrança duplicada no retry&lt;/a&gt;: ler, decidir e gravar como operações separadas, com uma janela no meio. Lá, a solução foi uma restrição única, que funciona quando a decisão cabe numa chave. Aqui o caso é outro: a decisão depende do &lt;strong&gt;valor lido&lt;/strong&gt;, e não existe chave que expresse isso.&lt;/p&gt;
&lt;p&gt;A diferença entre os dois bloqueios cabe numa frase, e é assim que o catálogo de padrões do Martin Fowler os descreve: &lt;strong&gt;bloqueio otimista é detecção de conflito; bloqueio pessimista é prevenção de conflito.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Uma boa analogia é o controle de versão&lt;/strong&gt;, que você usa todo dia. Duas pessoas precisam mexer no mesmo arquivo.&lt;/p&gt;
&lt;p&gt;No jeito otimista, o do Git (e antes dele o do CVS e do Subversion), as duas copiam o arquivo e editam à vontade, sem pedir permissão a ninguém. Quem termina primeiro envia sem problema. Quando a segunda tenta enviar, o sistema compara e recusa: &lt;em&gt;isto aqui mudou desde que você copiou.&lt;/em&gt; Ela junta as mudanças e envia de novo.&lt;/p&gt;
&lt;p&gt;No jeito pessimista, o de sistemas mais antigos no modelo “trava, modifica, destrava”, quem chega primeiro trava o arquivo. A segunda pessoa simplesmente não consegue editar até a primeira liberar. Conflito nunca acontece, porque nunca há duas edições ao mesmo tempo.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A frase carrega três consequências&lt;/strong&gt;, que valem mais do que ela:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Onde o custo cai.&lt;/strong&gt; No otimista, o caso normal é de graça: ninguém espera por ninguém, e só se paga quando o conflito de fato acontece. No pessimista, o custo é cobrado sempre: mesmo quando ninguém mais ia mexer naquela linha, o segundo espera do mesmo jeito. Um cobra por conflito; o outro cobra por acesso.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Quem lida com a falha.&lt;/strong&gt; &lt;strong&gt;Detecção produz erro, e erro precisa de dono: alguém relê, refaz e tenta outra vez. Prevenção produz espera.&lt;/strong&gt; Por isso o pessimista parece mais simples no código: no caso normal, não há caminho de exceção para escrever. O preço aparece no comportamento sob carga.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;O que acontece com o trabalho já feito.&lt;/strong&gt; No otimista, a segunda pessoa trabalhou e pode ter que jogar tudo fora. No pessimista, ela nem começou: ficou parada. &lt;strong&gt;Quando o trabalho é caro ou demorado, jogar fora dói; quando é barato, esperar dói mais.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A aposta de cada um está no próprio nome. O otimista aposta que conflito é raro; se estiver certo, você ganha concorrência de graça. O pessimista aposta que conflito é provável; se estiver certo, você evita um monte de trabalho perdido. &lt;strong&gt;Escolher entre os dois é uma aposta sobre a frequência de conflito na sua carga&lt;/strong&gt;, e isso se mede, não se escolhe por gosto.&lt;/p&gt;
&lt;h2 id=&quot;2-bloqueio-otimista&quot;&gt;2. Bloqueio otimista&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#2-bloqueio-otimista&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A aposta é que conflito é raro. Ninguém trava nada; todo mundo lê e trabalha à vontade. Na hora de gravar, a escrita carrega a pergunta junto: &lt;em&gt;o dado ainda está como eu li?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;A forma de fazer essa pergunta é uma &lt;strong&gt;coluna de versão&lt;/strong&gt;, um número inteiro que muda a cada gravação. Todo UPDATE incrementa a versão e filtra pela versão que foi lida. Se outra transação gravou antes, o filtro não encontra a linha e o banco devolve zero linhas afetadas. Zero linhas afetadas é a detecção do conflito.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cesarschutz.com.br/posts/bloqueio-otimista-e-pessimista/bloqueio-otimista.svg&quot; alt=&quot;Diagrama: bloqueio otimista. A e B leem a linha com version 1; A grava primeiro e a versão vira 2; o UPDATE de B filtra por version 1, afeta zero linhas e B precisa reler e tentar de novo&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Em SQL puro&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://cesarschutz.com.br/_astro/ec.bzl1c.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://cesarschutz.com.br/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;-- lido antes: saldo = 100, version = 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;UPDATE&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; conta&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;   &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;SET&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; saldo   &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;90&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;       &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;version&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;version&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; id &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;   &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;AND&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;version&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;-- UPDATE 1 -&gt; gravou&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;-- UPDATE 0 -&gt; alguém mudou a linha nesse meio-tempo&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;O ponto essencial: &lt;strong&gt;a verificação e a escrita são o mesmo comando&lt;/strong&gt;. Não existe janela entre uma e outra, e é por isso que funciona sem travar nada.&lt;/p&gt;
&lt;p&gt;Dá para usar uma coluna &lt;code&gt;updated_at&lt;/code&gt; no lugar da versão, mas um número inteiro é mais claro e não depende da precisão do relógio. A própria documentação do Hibernate diz que timestamp é uma forma menos confiável de bloqueio otimista do que número de versão.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Em Spring Data JPA&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;O Hibernate faz isso sozinho a partir de uma anotação:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;Conta.java&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;Entity&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;Conta&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;Id&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; Long id;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; BigDecimal saldo;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;Version&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;                 &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// habilita o bloqueio otimista&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; Long version;    &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// o Hibernate cuida do incremento&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Com isso, todo UPDATE que o Hibernate gera para a entidade inclui a versão no filtro (&lt;code&gt;update conta set saldo=?, version=? where id=? and version=?&lt;/code&gt;). Se nenhuma linha for afetada, o Hibernate lança &lt;code&gt;OptimisticLockException&lt;/code&gt; (da JPA), e o Spring a entrega traduzida como &lt;code&gt;ObjectOptimisticLockingFailureException&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Como o conflito agora é um erro, alguém precisa decidir o que fazer com ele. Uma resposta comum é tentar de novo. Desde o Spring Framework 7 (Spring Boot 4), a anotação &lt;code&gt;@Retryable&lt;/code&gt; faz parte do próprio framework e é habilitada com &lt;code&gt;@EnableResilientMethods&lt;/code&gt; numa classe de configuração:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;ContaService.java&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;Retryable&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;includes&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; ObjectOptimisticLockingFailureException.class,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;maxRetries&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;,          &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// 1 tentativa + 2 retentativas&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;delay&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;50&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;multiplier&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;jitter&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;25&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;Transactional&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;debitar&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(Long contaId, BigDecimal valor) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;Conta conta &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; repo.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;findById&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(contaId).&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;orElseThrow&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;conta.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;setSaldo&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(conta.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;getSaldo&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;subtract&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(valor));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;repo.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;save&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(conta);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Dois detalhes que sempre dão errado. Primeiro, o retry precisa &lt;strong&gt;reler&lt;/strong&gt; o dado: retentar com a entidade velha em mãos falha de novo, sempre. Aqui isso funciona porque o &lt;code&gt;@Retryable&lt;/code&gt; envolve o &lt;code&gt;@Transactional&lt;/code&gt;: cada tentativa abre uma transação nova e faz um &lt;code&gt;findById&lt;/code&gt; novo. Segundo, precisa de teto: três tentativas no total, não um laço infinito. Num teste com Spring Boot 4.1, forçando uma gravação concorrente na primeira tentativa, a segunda releu o saldo já alterado e gravou normalmente.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;O projeto Spring Retry, de onde vinha o &lt;code&gt;@Retryable&lt;/code&gt; com &lt;code&gt;retryFor&lt;/code&gt; e &lt;code&gt;@Backoff&lt;/code&gt;, foi arquivado e substituído pelos recursos de resiliência do Spring Framework 7. Em Spring Boot 3, ele ainda é o caminho.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;O que costuma passar batido:&lt;/strong&gt; a versão funciona mesmo entre requisições diferentes, separadas por minutos. Das duas técnicas de banco deste post, é a única que resolve o caso do usuário que abriu um formulário às 10h e salvou às 10h15: a transação no banco durou milissegundos, mas a versão lida às 10h continua sendo o critério. Basta a tela devolver a versão junto com os dados. É exatamente o padrão que o Fowler chama de &lt;em&gt;Optimistic Offline Lock&lt;/em&gt;; “offline” porque a proteção atravessa várias requisições, fora de uma única transação do banco.&lt;/p&gt;
&lt;h2 id=&quot;3-bloqueio-pessimista&quot;&gt;3. Bloqueio pessimista&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#3-bloqueio-pessimista&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A aposta é a inversa: conflito é provável, então é melhor não deixar acontecer. Quem chega primeiro trava a linha, e os outros esperam.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cesarschutz.com.br/posts/bloqueio-otimista-e-pessimista/bloqueio-pessimista.svg&quot; alt=&quot;Diagrama: bloqueio pessimista. A trava a linha com SELECT FOR UPDATE; B pede a mesma linha e fica esperando, sem erro; quando A faz COMMIT, B recebe a trava e lê o saldo já atualizado&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Em SQL puro&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;BEGIN&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; saldo&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;FROM&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; conta&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; id &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;   &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;FOR&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;UPDATE&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;;        &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;-- a partir daqui a linha está travada&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;-- a aplicação confere o saldo e decide&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;UPDATE&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; conta &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;SET&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; saldo &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; saldo &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; id &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;COMMIT&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;;               &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;-- a trava só sai aqui&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Quem pedir a mesma linha com &lt;code&gt;FOR UPDATE&lt;/code&gt; nesse meio-tempo fica esperando. Quando a primeira transação faz COMMIT, a segunda recebe a trava e lê a versão &lt;strong&gt;já atualizada&lt;/strong&gt; da linha, e não a que existia quando começou a esperar. É isso que impede o lost update.&lt;/p&gt;
&lt;p&gt;Três variações que vale conhecer no PostgreSQL:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;FOR UPDATE NOWAIT&lt;/code&gt;: em vez de esperar, falha na hora se a linha estiver travada (&lt;code&gt;could not obtain lock on row&lt;/code&gt;). Bom quando esperar é pior que desistir.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;FOR UPDATE SKIP LOCKED&lt;/code&gt;: pula as linhas travadas e devolve as outras. É assim que se implementa fila de trabalho em tabela: vários &lt;em&gt;workers&lt;/em&gt; pegam itens diferentes sem disputar o mesmo.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;lock_timeout&lt;/code&gt;: parâmetro de configuração que limita quanto tempo um comando espera por uma trava (por exemplo, &lt;code&gt;SET LOCAL lock_timeout = &apos;3s&apos;&lt;/code&gt; vale só para a transação atual). O padrão é &lt;code&gt;0&lt;/code&gt;, que desliga o limite: sem configurar, a espera é indefinida.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Em Spring Data JPA&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;ContaRepository.java&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;interface&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;ContaRepository&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;extends&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;JpaRepository&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;Conta&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;Long&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;Lock&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(LockModeType.PESSIMISTIC_WRITE)   &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// no PostgreSQL: SELECT ... FOR NO KEY UPDATE&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;QueryHints&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(@&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;QueryHint&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;jakarta.persistence.lock.timeout&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;3000&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;Query&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;select c from Conta c where c.id = :id&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;Optional&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;Conta&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;findByIdParaAtualizar&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(@&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;Param&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) Long &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Três cuidados com esse código:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;O SQL gerado não é exatamente &lt;code&gt;FOR UPDATE&lt;/code&gt;.&lt;/strong&gt; No PostgreSQL, o Hibernate traduz &lt;code&gt;PESSIMISTIC_WRITE&lt;/code&gt; para &lt;code&gt;FOR NO KEY UPDATE&lt;/code&gt;, uma trava um pouco mais fraca: bloqueia UPDATEs, DELETEs e outros &lt;code&gt;FOR UPDATE&lt;/code&gt; ou &lt;code&gt;FOR NO KEY UPDATE&lt;/code&gt; na linha, mas deixa passar o &lt;code&gt;FOR KEY SHARE&lt;/code&gt;, a trava mais leve de todas. Para o lost update, o efeito é o mesmo.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;O timeout depende da versão do Hibernate.&lt;/strong&gt; A dica &lt;code&gt;jakarta.persistence.lock.timeout&lt;/code&gt; (em milissegundos) só funciona no PostgreSQL em versões recentes do Hibernate 7, que executam &lt;code&gt;SET LOCAL lock_timeout&lt;/code&gt; antes da consulta. Em testes contra o PostgreSQL 17, ela funcionou no Hibernate 7.2.24, 7.3.13 e 7.4.5 (os de Spring Boot 4.0.8 e 4.1.1): a espera parou em 3 segundos com erro de trava (no Spring Boot 4.1, &lt;code&gt;CannotAcquireLockException&lt;/code&gt;). No Hibernate 6.6 (Spring Boot 3.5) e em 7.1.8, 7.2.0 e 7.3.0, foi ignorada sem aviso, e a espera continuou indefinida. Confirme na sua versão com um teste, ou defina &lt;code&gt;lock_timeout&lt;/code&gt; direto no banco, que vale para qualquer versão.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A trava precisa de uma transação em volta.&lt;/strong&gt; O método de serviço que chama esse repositório deve ser &lt;code&gt;@Transactional&lt;/code&gt;. Sem transação, a JPA recusa a consulta com trava (&lt;code&gt;TransactionRequiredException&lt;/code&gt;, que o Spring entrega como &lt;code&gt;InvalidDataAccessApiUsageException&lt;/code&gt;). E a trava só faz sentido se a leitura e a gravação estiverem na mesma transação, porque ela é liberada no fim dela.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;O que costuma passar batido:&lt;/strong&gt; a trava dura até o commit. Se dentro da transação você chamar o adquirente e ele levar 800 ms, a linha fica travada por 800 ms e todo mundo que quiser aquela linha entra na fila atrás. &lt;strong&gt;Não chame serviço externo com uma trava na mão.&lt;/strong&gt; Como separar a chamada externa da gravação local sem perder nenhuma das duas é o tema do post &lt;a href=&quot;https://cesarschutz.com.br/posts/efeito-externo-sem-registro-local/&quot;&gt;Efeito externo sem registro local&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;4-o-update-condicional-que-muitas-vezes-dispensa-os-dois&quot;&gt;4. O UPDATE condicional, que muitas vezes dispensa os dois&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#4-o-update-condicional-que-muitas-vezes-dispensa-os-dois&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Muita coisa que parece precisar de trava não precisa, porque dá para deixar o próprio banco fazer a conta:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;UPDATE&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; conta&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;   &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;SET&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; saldo &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; saldo &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;10&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; id &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;   &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;AND&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; saldo &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;-- UPDATE 1 -&gt; debitou&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;-- UPDATE 0 -&gt; saldo insuficiente&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Aqui não há leitura prévia na aplicação, então não há janela e não há lost update. O UPDATE trava a linha por conta própria enquanto grava. Se dois débitos chegam juntos, o segundo espera o primeiro terminar e, no nível de isolamento padrão do PostgreSQL, &lt;strong&gt;reavalia o &lt;code&gt;WHERE&lt;/code&gt; sobre o saldo já atualizado&lt;/strong&gt;. Num teste com saldo 15 e dois débitos simultâneos de 10, um afetou uma linha e o outro afetou zero, e o saldo terminou em 5.&lt;/p&gt;
&lt;p&gt;Essa é a primeira pergunta a fazer antes de escolher entre otimista e pessimista: &lt;strong&gt;dá para escrever isso como um único comando?&lt;/strong&gt; Se der, nenhum dos dois é necessário. No post sobre &lt;a href=&quot;https://cesarschutz.com.br/posts/arquitetura-de-ledger/&quot;&gt;arquitetura de ledger&lt;/a&gt;, a mesma ideia aparece como &lt;em&gt;balance locking&lt;/em&gt;: condicionar a escrita ao saldo em vez de à versão.&lt;/p&gt;
&lt;h2 id=&quot;5-como-escolher&quot;&gt;5. Como escolher&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#5-como-escolher&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;table-wrap&quot;&gt;







































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;Otimista&lt;/th&gt;&lt;th&gt;Pessimista&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Estratégia&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;detecta o conflito ao gravar&lt;/td&gt;&lt;td&gt;evita o conflito antes&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Custo no caso normal&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;nenhum: ninguém espera&lt;/td&gt;&lt;td&gt;espera de quem chega depois&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Custo sob disputa&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;retentativas, que podem virar avalanche&lt;/td&gt;&lt;td&gt;fila, e risco de deadlock&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Quem trata a falha&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;a aplicação, relendo e tentando de novo&lt;/td&gt;&lt;td&gt;ninguém no caso normal; timeout e deadlock ainda viram erro&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Funciona entre requisições?&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;sim, com a versão indo e voltando&lt;/td&gt;&lt;td&gt;não com trava de banco, que só vive dentro da transação&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Onde encaixa&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;conflito raro, leitura pesada, edição por tela&lt;/td&gt;&lt;td&gt;conflito frequente, operação crítica, transação curta&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Na descrição do Fowler, o pessimista limita a concorrência do sistema, enquanto o otimista deixa várias pessoas trabalharem nos mesmos dados ao mesmo tempo. Na prática, isso leva a uma regra que funciona bem: comece otimista, que é mais simples e não cria filas. A pergunta certa não é “quando usar o otimista”, e sim &lt;strong&gt;“quando o otimista sozinho não basta”&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;No meu domínio, o critério prático é a taxa de disputa pela mesma linha. Cadastro de cooperado, limite, parâmetro de produto: otimista. Saldo de uma única conta em dia de pico, ou contador de uso de limite: pessimista ou, melhor ainda, um único UPDATE condicional.&lt;/p&gt;
&lt;h2 id=&quot;6-padrões-nomeados&quot;&gt;6. Padrões nomeados&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#6-padrões-nomeados&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Já explicados acima; aqui fica só o nome formal&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Lost update&lt;/strong&gt;: duas leituras, dois cálculos, duas escritas, e uma delas desaparece sem erro. &lt;em&gt;Onde mais aparece:&lt;/em&gt; contador de estoque, saldo, qualquer campo calculado a partir do valor lido.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Optimistic Offline Lock&lt;/strong&gt;: nome do padrão no catálogo do Fowler. “Offline” porque a proteção vale além de uma transação do banco, atravessando requisições. &lt;em&gt;Onde mais aparece:&lt;/em&gt; &lt;code&gt;ETag&lt;/code&gt; com &lt;code&gt;If-Match&lt;/code&gt; em HTTP, que a RFC 9110 descreve justamente como proteção contra o lost update; o campo &lt;code&gt;_rev&lt;/code&gt; no CouchDB, que recusa com 409 a gravação feita sobre uma revisão antiga; edição concorrente de documentos.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pessimistic Offline Lock&lt;/strong&gt;: o par do anterior. Como a trava de banco não sobrevive ao fim da transação, aqui a trava é da aplicação: um registro (numa tabela de travas, por exemplo) dizendo quem está editando o quê, obtido antes de começar e liberado no fim. &lt;em&gt;Onde mais aparece:&lt;/em&gt; check-out de arquivo em sistemas de versão antigos, reserva de assento, qualquer “só um por vez”.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Mencionados de passagem; vale saber o que são&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Deadlock&lt;/strong&gt;: duas transações travam as mesmas linhas em ordem invertida e ficam esperando uma pela outra para sempre. O PostgreSQL detecta o ciclo (a checagem roda depois de &lt;code&gt;deadlock_timeout&lt;/code&gt;, 1 segundo por padrão) e aborta uma das duas com &lt;code&gt;deadlock detected&lt;/code&gt;. A prevenção é simples e quase nunca feita: &lt;strong&gt;travar sempre na mesma ordem&lt;/strong&gt;, por exemplo ordenando por id. É um risco típico do pessimista, mas não exclusivo dele: um UPDATE comum também trava a linha até o commit, então duas transações que atualizam as mesmas contas em ordem invertida podem entrar em deadlock mesmo sem &lt;code&gt;FOR UPDATE&lt;/code&gt;, com ou sem coluna de versão.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Níveis de isolamento&lt;/strong&gt;: a outra forma de tratar concorrência, no nível da transação inteira em vez de linha a linha. O PostgreSQL usa READ COMMITTED por padrão, que &lt;strong&gt;não&lt;/strong&gt; impede o lost update do padrão “leu na aplicação, calculou, gravou”; daí a necessidade de bloqueio explícito. Em REPEATABLE READ e SERIALIZABLE, o PostgreSQL impede, mas abortando a segunda transação com &lt;code&gt;could not serialize access due to concurrent update&lt;/code&gt;, e a aplicação precisa saber retentar. &lt;em&gt;Vale saber que existe:&lt;/em&gt; é pergunta clássica de entrevista para vaga sênior.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;SELECT ... FOR UPDATE SKIP LOCKED&lt;/code&gt; como fila&lt;/strong&gt;: truque para usar uma tabela como fila de trabalho sem &lt;em&gt;broker&lt;/em&gt; de mensagens. A documentação do PostgreSQL cita exatamente esse uso: evitar disputa entre vários consumidores de uma tabela que funciona como fila. &lt;em&gt;Por que importa:&lt;/em&gt; permite processar lotes com vários workers em paralelo sem que dois peguem o mesmo item.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;7-onde-eu-apertaria-numa-entrevista&quot;&gt;7. Onde eu apertaria numa entrevista&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#7-onde-eu-apertaria-numa-entrevista&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Você colocou &lt;code&gt;@Version&lt;/code&gt; e o conflito virou exceção. Quem trata? E o que o usuário final vê?&lt;/li&gt;
&lt;li&gt;Sob disputa alta, o otimista entra em avalanche de retentativas. Como você percebe isso antes do cliente?&lt;/li&gt;
&lt;li&gt;Uma transação com &lt;code&gt;FOR UPDATE&lt;/code&gt; chama o adquirente por dentro. O que acontece com as outras requisições daquela conta?&lt;/li&gt;
&lt;li&gt;Como você evita deadlock quando precisa travar duas linhas na mesma transação?&lt;/li&gt;
&lt;li&gt;O time quer subir o isolamento para SERIALIZABLE e “resolver de uma vez”. Que argumento você traz?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;fontes&quot;&gt;Fontes&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#fontes&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Martin Fowler — &lt;a href=&quot;https://www.martinfowler.com/eaaCatalog/optimisticOfflineLock.html&quot;&gt;Optimistic Offline Lock&lt;/a&gt; (&lt;em&gt;Patterns of Enterprise Application Architecture&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;Martin Fowler — &lt;a href=&quot;https://martinfowler.com/eaaCatalog/pessimisticOfflineLock.html&quot;&gt;Pessimistic Offline Lock&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Version Control with Subversion — &lt;a href=&quot;https://svnbook.red-bean.com/en/1.7/svn.basic.version-control-basics.html&quot;&gt;Version Control Basics (lock-modify-unlock e copy-modify-merge)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;PostgreSQL — &lt;a href=&quot;https://www.postgresql.org/docs/current/explicit-locking.html&quot;&gt;Explicit Locking (modos de trava de linha e deadlocks)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;PostgreSQL — &lt;a href=&quot;https://www.postgresql.org/docs/current/sql-select.html&quot;&gt;SELECT: cláusula de trava (NOWAIT, SKIP LOCKED)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;PostgreSQL — &lt;a href=&quot;https://www.postgresql.org/docs/current/runtime-config-client.html&quot;&gt;Client Connection Defaults (&lt;code&gt;lock_timeout&lt;/code&gt;)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;PostgreSQL — &lt;a href=&quot;https://www.postgresql.org/docs/current/transaction-iso.html&quot;&gt;Transaction Isolation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Hibernate ORM — &lt;a href=&quot;https://docs.hibernate.org/orm/current/userguide/html_single/Hibernate_User_Guide.html#locking&quot;&gt;User Guide: Locking&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Hibernate ORM — &lt;a href=&quot;https://github.com/hibernate/hibernate-orm/blob/7.4.5/hibernate-core/src/main/java/org/hibernate/dialect/lock/internal/PostgreSQLLockingSupport.java&quot;&gt;&lt;code&gt;PostgreSQLLockingSupport&lt;/code&gt; (aplicação do lock timeout via &lt;code&gt;SET LOCAL lock_timeout&lt;/code&gt;)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Spring Data JPA — &lt;a href=&quot;https://docs.spring.io/spring-data/jpa/reference/jpa/locking.html&quot;&gt;Locking&lt;/a&gt; e &lt;a href=&quot;https://docs.spring.io/spring-data/jpa/reference/jpa/transactions.html&quot;&gt;Transactionality&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Spring Framework — &lt;a href=&quot;https://docs.spring.io/spring-framework/reference/core/resilience.html&quot;&gt;Resilience Features (&lt;code&gt;@Retryable&lt;/code&gt;)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Spring Retry — &lt;a href=&quot;https://github.com/spring-projects/spring-retry&quot;&gt;repositório (arquivado, substituído pelo Spring Framework 7)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;IETF — &lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc9110.html#section-13.1.1&quot;&gt;RFC 9110, HTTP Semantics (requisições condicionais e o “lost update”)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Apache CouchDB — &lt;a href=&quot;https://docs.couchdb.org/en/stable/api/document/common.html&quot;&gt;API de documentos (&lt;code&gt;_rev&lt;/code&gt; e 409 Conflict)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Vlad Mihalcea — &lt;a href=&quot;https://vladmihalcea.com/tag/explicit-locking/&quot;&gt;artigos sobre explicit locking em JPA e Hibernate&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Stormatics — &lt;a href=&quot;https://stormatics.tech/blogs/ensuring-safe-data-modifications-in-postgresql-part-2&quot;&gt;Ensuring Safe Data Modifications in PostgreSQL, parte 2 (bloqueio otimista)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>Arquitetura</category><category>Banco de Dados</category><category>Concorrência</category><category>Spring</category><category>Trade-offs</category></item><item><title>Virtual threads no Java 21 — pinning e CLOSE_WAIT</title><link>https://cesarschutz.com.br/posts/virtual-threads-pinning-close-wait/</link><guid isPermaLink="true">https://cesarschutz.com.br/posts/virtual-threads-pinning-close-wait/</guid><description>Por que um serviço Java 21 com virtual threads congela sem erro no log: pinning por synchronized (resolvido no Java 24, JEP 491) e CLOSE_WAIT como rastro. Thread dump, JFR, bulkhead e circuit breaker.</description><pubDate>Sat, 12 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Um serviço Java 21 com virtual threads para de responder no pico, sem nenhum erro no log, e o host acumula milhares de sockets em CLOSE_WAIT. Este post segue o diagnóstico em formato de desafio: primeiro o sintoma, depois a resposta que parecia certa, onde ela falhou e a causa real, o &lt;strong&gt;pinning&lt;/strong&gt; de virtual threads dentro de blocos &lt;code&gt;synchronized&lt;/code&gt;. Em seguida vem o que continua valendo mesmo depois da correção: limites explícitos com bulkhead e circuit breaker, com código Java que você pode rodar.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Em quais versões isso acontece.&lt;/strong&gt; O pinning por &lt;code&gt;synchronized&lt;/code&gt; existe do &lt;strong&gt;Java 21 ao 23&lt;/strong&gt;. O Java 24 corrigiu o problema com a &lt;a href=&quot;https://openjdk.org/jeps/491&quot;&gt;JEP 491&lt;/a&gt;, e o &lt;strong&gt;Java 25 é a primeira LTS com a correção&lt;/strong&gt;. As seções 6 e 7 (gargalo, bulkhead e circuit breaker) valem para qualquer versão. O modelo de virtual threads está no &lt;a href=&quot;https://cesarschutz.com.br/posts/java-21/#virtual-threads&quot;&gt;post do Java 21&lt;/a&gt; e a correção, no &lt;a href=&quot;https://cesarschutz.com.br/posts/java-25/#synchronized-n%C3%A3o-prende-mais-virtual-threads&quot;&gt;post do Java 25&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;1-desafio&quot;&gt;1. Desafio&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#1-desafio&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Enunciado.&lt;/strong&gt; Serviço de autorização de cartões, Spring Boot 3 com Tomcat embarcado, Java 21. O time ligou virtual threads para processar as requisições (&lt;code&gt;spring.threads.virtual.enabled=true&lt;/code&gt;, disponível a partir do Spring Boot 3.2). Cada autorização chama o &lt;strong&gt;adquirente&lt;/strong&gt;, a empresa que processa a transação de cartão para o lojista.&lt;/p&gt;
&lt;p&gt;Dois dias depois, no pico da tarde, uma instância para de responder. Não devolve erro: simplesmente não responde. O health check estoura o tempo, o Kubernetes reinicia o pod, e tudo volta ao normal por algumas horas.&lt;/p&gt;
&lt;p&gt;Os sinais:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A JVM está viva. Sem OutOfMemoryError, sem exceção, sem stack trace no log.&lt;/li&gt;
&lt;li&gt;CPU baixa, memória estável, GC comportado.&lt;/li&gt;
&lt;li&gt;No host, milhares de sockets em CLOSE_WAIT.&lt;/li&gt;
&lt;li&gt;Não reproduz em homologação. O teste de carga sintético passa limpo.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;O que está acontecendo?&lt;/p&gt;
&lt;h2 id=&quot;2-vocabulário-que-faltava&quot;&gt;2. Vocabulário que faltava&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#2-vocabulário-que-faltava&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;O diagnóstico começa pelo vocabulário: sem ele, o raciocínio trava. São quatro peças.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Socket&lt;/strong&gt; — a ponta que cada lado segura numa conexão de rede. Funciona como o telefone numa ligação: enquanto a ligação existe, ele está ocupado. Cada requisição HTTP em curso usa um, e socket é recurso finito: cada um conta no limite de arquivos abertos do processo.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;CLOSE_WAIT&lt;/strong&gt; — estado TCP que significa “o outro lado desligou, o seu ainda não”. Encerrar uma conexão exige que os dois lados desliguem, e quem desliga do seu lado é a aplicação, chamando &lt;code&gt;close()&lt;/code&gt;, não o sistema operacional (&lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc9293&quot;&gt;RFC 9293&lt;/a&gt;). Milhares de sockets nesse estado significam que o código parou de chegar à linha que fecha a conexão.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Platform thread&lt;/strong&gt; — a thread tradicional do Java, que corresponde a uma thread do sistema operacional (SO). É cara: só a pilha reserva 1 MB por padrão no Linux x64 (&lt;a href=&quot;https://docs.oracle.com/en/java/javase/21/docs/specs/man/java.html&quot;&gt;documentação do &lt;code&gt;java&lt;/code&gt;&lt;/a&gt;). Por isso ninguém cria uma por requisição: cria-se um pool, e as requisições se revezam. O Tomcat do Spring Boot usa, por padrão, até 200 (&lt;a href=&quot;https://docs.spring.io/spring-boot/appendix/application-properties/index.html#application-properties.server.server.tomcat.threads.max&quot;&gt;&lt;code&gt;server.tomcat.threads.max&lt;/code&gt;&lt;/a&gt;). O desperdício aparece quando o trabalho é esperar: 300 ms esperando o adquirente são 300 ms de uma thread ocupada sem fazer nada.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Virtual thread&lt;/strong&gt; — thread gerenciada pela JVM, não pelo SO. É barata a ponto de uma JVM poder ter milhões (&lt;a href=&quot;https://openjdk.org/jeps/444&quot;&gt;JEP 444&lt;/a&gt;). Ela não substitui as threads reais: para executar, é &lt;strong&gt;montada&lt;/strong&gt; sobre uma das poucas &lt;strong&gt;carrier threads&lt;/strong&gt;, que são platform threads de um pool da JVM (por padrão, uma por processador disponível). Quando a virtual thread bloqueia em I/O, a JVM normalmente a &lt;strong&gt;desmonta&lt;/strong&gt; da carrier e coloca outra no lugar. É esse revezamento que faz o modelo funcionar.&lt;/p&gt;
&lt;h2 id=&quot;3-resposta-dada&quot;&gt;3. Resposta dada&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#3-resposta-dada&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;O microsserviço para de responder porque não tem thread disponível. O problema deve estar nos sockets em CLOSE_WAIT — teria que descobrir por que a aplicação não está encerrando os sockets.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;4-onde-furou&quot;&gt;4. Onde furou&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#4-onde-furou&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Dois ajustes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Não faltou virtual thread, faltou carrier.&lt;/strong&gt; Virtual thread é barata, e a JVM cria quantas forem precisas. O gargalo é o punhado de threads reais embaixo delas. Se cada carrier fica presa a uma virtual thread que bloqueou e não desmontou, pode haver dezenas de milhares de virtual threads prontas, e nenhuma consegue executar. Esse estado tem nome: &lt;strong&gt;pinning&lt;/strong&gt; (a virtual thread fica “pregada” à carrier).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A causalidade é a inversa.&lt;/strong&gt; O CLOSE_WAIT não é a causa, é a impressão digital. As carriers travaram, então o código parou de rodar, então ninguém chegou à linha que fecha o socket. Os clientes estouraram o timeout e desligaram do lado deles. Milhares de CLOSE_WAIT são o retrato de uma aplicação congelada, não de um bug no fechamento de conexões.&lt;/p&gt;
&lt;p&gt;O diagrama mostra a cadeia completa, do pico de requisições até os sockets em CLOSE_WAIT:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cesarschutz.com.br/posts/virtual-threads-pinning-close-wait/pinning-virtual-threads.svg&quot; alt=&quot;Diagrama: no Java 21 a 23, as virtual threads montadas nas 4 carriers bloqueiam dentro de synchronized e prendem as carriers; as demais esperam, ninguém fecha os sockets e eles se acumulam em CLOSE_WAIT; no Java 24 em diante, a JEP 491 corrige o synchronized&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;5-aprendizado--pinning-java-21-a-23&quot;&gt;5. Aprendizado — pinning (Java 21 a 23)&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#5-aprendizado--pinning-java-21-a-23&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;No Java 21, a virtual thread fica presa à carrier em dois casos (&lt;a href=&quot;https://openjdk.org/jeps/444&quot;&gt;JEP 444&lt;/a&gt;): quando bloqueia &lt;strong&gt;dentro de um bloco ou método &lt;code&gt;synchronized&lt;/code&gt;&lt;/strong&gt;, e durante um método nativo ou função estrangeira. O primeiro é o que pesa: segundo a JEP 491, resolvê-lo elimina quase todos os casos de pinning.&lt;/p&gt;
&lt;p&gt;O motivo é interno da JVM. Até o Java 23, ela registra como dona do monitor de um objeto (o lock que o &lt;code&gt;synchronized&lt;/code&gt; adquire) a &lt;strong&gt;platform thread&lt;/strong&gt;, ou seja, a carrier, e não a virtual thread. Se a virtual thread desmontasse ali dentro, outra virtual thread montada na mesma carrier pareceria dona do monitor, e a exclusão mútua se perderia (&lt;a href=&quot;https://openjdk.org/jeps/491&quot;&gt;JEP 491&lt;/a&gt;). Então a JVM não desmonta: a carrier fica bloqueada junto. E a JEP 444 é explícita: o escalonador &lt;strong&gt;não compensa&lt;/strong&gt; o pinning criando carriers extras.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Veja acontecer.&lt;/strong&gt; O programa abaixo roda 100 tarefas que esperam 100 ms cada, uma vez segurando um &lt;code&gt;synchronized&lt;/code&gt; e outra segurando um &lt;code&gt;ReentrantLock&lt;/code&gt;. Cada tarefa tem o próprio lock, então ninguém disputa nada: a única diferença é o tipo de lock.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://cesarschutz.com.br/_astro/ec.bzl1c.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://cesarschutz.com.br/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;CarrierPresa.java&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; java.time.Duration;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; java.time.Instant;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; java.util.concurrent.ExecutorService;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; java.util.concurrent.Executors;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; java.util.concurrent.locks.ReentrantLock;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; java.util.stream.IntStream;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;CarrierPresa&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;esperarAdquirente&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;try&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;Thread.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;sleep&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;100&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;); &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// espera de I/O: aqui a virtual thread deveria desmontar&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;catch&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (InterruptedException &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;Thread.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;currentThread&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;interrupt&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;comSynchronized&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;Object monitor &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;Object&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(); &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// um por tarefa: ninguém disputa o lock&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;synchronized&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (monitor) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;esperarAdquirente&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;comReentrantLock&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;ReentrantLock lock &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;ReentrantLock&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(); &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// um por tarefa, como acima&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;lock.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;lock&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;try&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;esperarAdquirente&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;finally&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;lock.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;unlock&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;long&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;medir&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(Runnable &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;tarefa&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;Instant inicio &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; Instant.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;now&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;try&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (ExecutorService executor &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; Executors.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;newVirtualThreadPerTaskExecutor&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;()) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;IntStream.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;range&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;100&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;forEach&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(i &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; executor.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;submit&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(tarefa));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; Duration.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;between&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(inicio, Instant.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;now&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;()).&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;toMillis&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;main&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;[] &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;args&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;System.out.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;Java &quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; Runtime.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;version&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;feature&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;());&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;System.out.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;synchronized:  &quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;medir&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(CarrierPresa&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;comSynchronized) &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot; ms&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;System.out.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;ReentrantLock: &quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;medir&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(CarrierPresa&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;comReentrantLock) &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot; ms&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Rodando com 4 carriers, como numa máquina de 4 vCPUs, nas imagens &lt;code&gt;eclipse-temurin:21&lt;/code&gt; e &lt;code&gt;eclipse-temurin:25&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;Saída&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#e1e4e8;--1:#24292e&quot;&gt;$ java -Djdk.virtualThreadScheduler.parallelism=4 CarrierPresa.java&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#e1e4e8;--1:#24292e&quot;&gt;Java 21&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#e1e4e8;--1:#24292e&quot;&gt;synchronized:  2581 ms&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#e1e4e8;--1:#24292e&quot;&gt;ReentrantLock: 106 ms&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#e1e4e8;--1:#24292e&quot;&gt;$ java -Djdk.virtualThreadScheduler.parallelism=4 CarrierPresa.java&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#e1e4e8;--1:#24292e&quot;&gt;Java 25&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#e1e4e8;--1:#24292e&quot;&gt;synchronized:  149 ms&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#e1e4e8;--1:#24292e&quot;&gt;ReentrantLock: 104 ms&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;No Java 21, com &lt;code&gt;synchronized&lt;/code&gt;, só 4 tarefas avançam por vez: 100 tarefas ÷ 4 carriers × 100 ms ≈ 2,5 s. Com &lt;code&gt;ReentrantLock&lt;/code&gt;, as 100 esperam juntas. No Java 25, os dois casos se comportam igual. Os tempos exatos variam de máquina para máquina; a proporção é o que importa.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Nem sempre o &lt;code&gt;synchronized&lt;/code&gt; está no seu código.&lt;/strong&gt; A Netflix documentou exatamente esse quadro em julho de 2024: Spring Boot 3, Tomcat embarcado, Java 21, instâncias que paravam de responder e sockets acumulados em CLOSE_WAIT. Ali, o &lt;code&gt;synchronized&lt;/code&gt; vinha da biblioteca de tracing Brave (em &lt;code&gt;RealSpan.finish&lt;/code&gt;). Dentro dele, as virtual threads esperavam um &lt;code&gt;ReentrantLock&lt;/code&gt; do reporter do Zipkin. As instâncias tinham 4 vCPUs, portanto 4 carriers. Com as quatro presas, quando o lock era liberado, a virtual thread que deveria recebê-lo não tinha carrier para executar, e nada mais andava. Os sockets em CLOSE_WAIT batiam com milhares de virtual threads que o Tomcat tinha criado e que nunca chegaram a executar.&lt;/p&gt;
&lt;p&gt;É também por isso que homologação passa limpo: pinning só vira travamento quando há concorrência suficiente para prender todas as carriers ao mesmo tempo. Com carga baixa, uma carrier presa passa despercebida.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Como se descobre&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Thread dump no formato novo.&lt;/strong&gt; O dump tradicional (&lt;code&gt;jstack&lt;/code&gt; ou &lt;code&gt;jcmd &amp;#x3C;pid&gt; Thread.print&lt;/code&gt;) &lt;strong&gt;não mostra virtual threads&lt;/strong&gt; (&lt;a href=&quot;https://openjdk.org/jeps/444&quot;&gt;JEP 444&lt;/a&gt;); foi o que confundiu a Netflix no começo, porque o dump parecia ocioso. Use &lt;code&gt;jcmd &amp;#x3C;pid&gt; Thread.dump_to_file -format=text dump.txt&lt;/code&gt; (ou &lt;code&gt;-format=json&lt;/code&gt;; o nome do arquivo é obrigatório). Nele, as carriers (&lt;code&gt;ForkJoinPool-1-worker-N&lt;/code&gt;) aparecem executando &lt;code&gt;Continuation.run&lt;/code&gt;, e as virtual threads montadas nelas aparecem paradas no mesmo ponto, dentro do &lt;code&gt;synchronized&lt;/code&gt;. Esse ponto é a resposta. As demais virtual threads aparecem sem stack: foram criadas e esperam uma carrier.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;JFR (JDK Flight Recorder)&lt;/strong&gt;, o gravador de eventos embutido na JVM. O evento &lt;code&gt;jdk.VirtualThreadPinned&lt;/code&gt; registra, com stack trace, cada vez que uma virtual thread fica parada presa à carrier por mais de 20 ms, o limiar padrão. O evento vem habilitado, mas só é gravado se houver uma gravação ativa: &lt;code&gt;java -XX:StartFlightRecording=filename=rec.jfr ...&lt;/code&gt; e depois &lt;code&gt;jfr print --events jdk.VirtualThreadPinned rec.jfr&lt;/code&gt;. No &lt;code&gt;CarrierPresa.java&lt;/code&gt;, o Java 21 grava 100 eventos, um por tarefa com &lt;code&gt;synchronized&lt;/code&gt;; o Java 25 grava zero. Manter o evento ligado em produção, com alerta, é uma das recomendações do &lt;a href=&quot;https://www.infoq.com/articles/virtual-threads-after-jdk24/&quot;&gt;artigo da InfoQ&lt;/a&gt; citado nas fontes.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;-Djdk.tracePinnedThreads=short&lt;/code&gt;&lt;/strong&gt; (ou &lt;code&gt;full&lt;/code&gt;), &lt;strong&gt;só do Java 21 ao 23&lt;/strong&gt;. Imprime o stack sempre que uma virtual thread bloqueia presa, e o frame marcado aponta o &lt;code&gt;synchronized&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#e1e4e8;--1:#24292e&quot;&gt;VirtualThread[#25]/runnable@ForkJoinPool-1-worker-2 reason:MONITOR&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#e1e4e8;--1:#24292e&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#e1e4e8;--1:#24292e&quot;&gt;CarrierPresa.comSynchronized(CarrierPresa.java:21) &amp;#x3C;== monitors:1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;A JEP 491 removeu essa propriedade no Java 24.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Como se resolve&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Subir para o Java 24 ou mais novo&lt;/strong&gt;, na prática para o &lt;strong&gt;Java 25&lt;/strong&gt;, a primeira LTS com a JEP 491. A partir dela, a virtual thread desmonta ao bloquear dentro de &lt;code&gt;synchronized&lt;/code&gt; ou em &lt;code&gt;Object.wait()&lt;/code&gt;. É o conserto definitivo e vale também para o &lt;code&gt;synchronized&lt;/code&gt; das dependências. Os detalhes estão no &lt;a href=&quot;https://cesarschutz.com.br/posts/java-25/#synchronized-n%C3%A3o-prende-mais-virtual-threads&quot;&gt;post do Java 25&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Trocar &lt;code&gt;synchronized&lt;/code&gt; por &lt;code&gt;ReentrantLock&lt;/code&gt;&lt;/strong&gt;, se o serviço fica no Java 21. É a mesma exclusão mútua, mas a espera não prende a carrier. A JEP 444 recomenda a troca só onde o bloco roda com frequência e protege I/O potencialmente longo; blocos raros ou que só protegem operações em memória podem ficar como estão. No Java 24 em diante, a JEP 491 volta a recomendar &lt;code&gt;synchronized&lt;/code&gt; onde for prático.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Atualizar a dependência&lt;/strong&gt;, se o &lt;code&gt;synchronized&lt;/code&gt; está numa biblioteca e uma versão nova já trocou o lock. Se não trocou, não há o que refatorar no seu código: resta subir o Java.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Um upgrade de Java leva semanas, e no plantão a mitigação imediata é outra: desligar as virtual threads por configuração (&lt;code&gt;spring.threads.virtual.enabled=false&lt;/code&gt;) e voltar ao pool tradicional. Perde escalabilidade, mas para de cair. Curativo e conserto são coisas separadas.&lt;/p&gt;
&lt;h2 id=&quot;6-aprendizado--o-gargalo-mudou-de-lugar&quot;&gt;6. Aprendizado — o gargalo mudou de lugar&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#6-aprendizado--o-gargalo-mudou-de-lugar&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;O Java 25 resolve o pinning por &lt;code&gt;synchronized&lt;/code&gt;, mas não resolve o que vem junto com as virtual threads. Esta parte vale para qualquer versão.&lt;/p&gt;
&lt;p&gt;No modelo antigo, o pool de 200 threads do Tomcat fazia dois trabalhos sem ninguém perceber: separava o trabalho de cada requisição &lt;strong&gt;e&lt;/strong&gt; limitava quantas requisições estavam em andamento, portanto quantas chamadas saíam do serviço ao mesmo tempo. Com virtual threads, cada requisição ganha a sua thread, e o segundo trabalho desaparece. A propriedade &lt;code&gt;server.tomcat.threads.max&lt;/code&gt; nem tem efeito quando as virtual threads estão ligadas.&lt;/p&gt;
&lt;p&gt;Chegam 10 mil requisições no pico:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;No Postgres&lt;/strong&gt;, nada é derrubado de imediato: forma-se fila. O pool de conexões do HikariCP tem teto (o padrão é 10; digamos que o time configurou 20). Vinte requisições pegam conexão e o resto espera. Quem não consegue conexão em 30 segundos, o &lt;code&gt;connectionTimeout&lt;/code&gt; padrão, recebe erro, e isso acontece em massa (&lt;a href=&quot;https://github.com/brettwooldridge/HikariCP&quot;&gt;HikariCP&lt;/a&gt;). Essa fila não existia antes: com 200 threads, no máximo 200 requisições pediam conexão, e as demais nem tinham começado.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No adquirente&lt;/strong&gt;, é pior, porque o problema sai de casa. Milhares de chamadas simultâneas chegam a um terceiro com contrato para 500. Ele recusa ou fica lento, e aí você tem milhares de conexões abertas esperando.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Virtual threads não eliminam gargalo, mudam o gargalo de lugar.&lt;/strong&gt; O conserto é tornar explícito o que era implícito: um limite declarado em cada recurso compartilhado, com o número decidido por você em vez de herdado do tamanho do pool.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cesarschutz.com.br/posts/virtual-threads-pinning-close-wait/gargalo-mudou-de-lugar.svg&quot; alt=&quot;Diagrama: antes, o pool de 200 threads separava o trabalho e limitava a saída; depois, 10.000 virtual threads sem limite formam fila no Postgres e sobrecarregam o adquirente; o conserto é bulkhead, circuit breaker e limite também antes do banco&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;7-as-três-peças-juntas&quot;&gt;7. As três peças juntas&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#7-as-três-peças-juntas&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;São três trabalhos diferentes, e nenhum substitui o outro:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Virtual threads dão vazão&lt;/strong&gt;, isto é, mais trabalho em andamento ao mesmo tempo. Não deixam nada mais rápido: se o adquirente leva 300 ms, continua levando 300 ms. O que muda é quantas requisições cabem simultaneamente.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bulkhead limita a saída.&lt;/strong&gt; É preventivo e funciona o tempo todo: declara quantas chamadas simultâneas podem sair do serviço para um destino. Devolve o limite que o pool de threads dava de graça.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Circuit breaker interrompe.&lt;/strong&gt; É reativo e só age quando o destino está mal: percebe a sequência de falhas e para de insistir por um tempo.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Um sem o outro deixa buraco. Se o adquirente está lento, só com o bulkhead cada requisição ainda espera até 200 ms por uma vaga (o &lt;code&gt;maxWaitDuration&lt;/code&gt; dos exemplos abaixo), mais o tempo da própria chamada, para descobrir o que as últimas dezenas de falhas já tinham mostrado.&lt;/p&gt;
&lt;h3 id=&quot;vazão--o-efeito-das-virtual-threads&quot;&gt;Vazão — o efeito das virtual threads&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#vazão--o-efeito-das-virtual-threads&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Roda direto com &lt;code&gt;java Vazao.java&lt;/code&gt; no Java 21 ou mais novo, sem dependência nenhuma. O &lt;code&gt;Thread.sleep&lt;/code&gt; faz o papel da chamada ao adquirente.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;Vazao.java&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; java.time.Duration;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; java.time.Instant;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; java.util.concurrent.ExecutorService;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; java.util.concurrent.Executors;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; java.util.stream.IntStream;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;Vazao&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;chamadaAoAdquirente&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;try&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;Thread.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;sleep&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;300&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;); &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// espera de I/O: a thread não faz nada aqui&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;catch&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (InterruptedException &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;Thread.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;currentThread&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;interrupt&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;long&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;medir&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(ExecutorService &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;executor&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;Instant inicio &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; Instant.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;now&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;try&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (executor) { &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// close() espera todas terminarem&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;IntStream.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;range&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;1000&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;                     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;forEach&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(i &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; executor.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;submit&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(Vazao&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;chamadaAoAdquirente));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; Duration.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;between&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(inicio, Instant.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;now&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;()).&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;toMillis&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;main&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;[] &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;args&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;System.out.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;pool de 200 threads: &quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;medir&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(Executors.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;newFixedThreadPool&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;200&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;)) &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot; ms&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;System.out.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;virtual threads:     &quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;medir&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(Executors.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;newVirtualThreadPerTaskExecutor&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;()) &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot; ms&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;Saída (eclipse-temurin:21)&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#e1e4e8;--1:#24292e&quot;&gt;pool de 200 threads: 1623 ms&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#e1e4e8;--1:#24292e&quot;&gt;virtual threads:     324 ms&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;São mil chamadas de 300 ms. Com 200 threads, elas saem em cinco levas: no mínimo 1500 ms, um pouco mais na prática, porque criar as threads também custa. Com virtual threads, todas ficam em andamento juntas, perto de 300 ms. É esse número que deveria acender a luz amarela: mil chamadas simultâneas saindo para um terceiro.&lt;/p&gt;
&lt;h3 id=&quot;bulkhead--o-limite-sem-dependência&quot;&gt;Bulkhead — o limite, sem dependência&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#bulkhead--o-limite-sem-dependência&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Também roda sozinho. O &lt;code&gt;Semaphore&lt;/code&gt; limita a 100 as chamadas simultâneas, e o programa mostra o pico real de chamadas em andamento e quantas foram recusadas pelo próprio serviço.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;BulkheadSimples.java&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; java.util.concurrent.Executors;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; java.util.concurrent.ExecutorService;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; java.util.concurrent.Semaphore;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; java.util.concurrent.TimeUnit;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; java.util.concurrent.atomic.AtomicInteger;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; java.util.stream.IntStream;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;BulkheadSimples&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;final&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; Semaphore limite &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;Semaphore&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;100&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;final&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; AtomicInteger emVoo &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;AtomicInteger&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;final&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; AtomicInteger pico &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;AtomicInteger&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;final&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; AtomicInteger recusadas &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;AtomicInteger&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;capturar&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;entrar&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;()) {              &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// não conseguiu vaga a tempo&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;recusadas.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;incrementAndGet&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;;                   &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// recusa rápida, decidida por você&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;try&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; agora &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; emVoo.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;incrementAndGet&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;pico.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;updateAndGet&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(p &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; Math.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;max&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(p, agora));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;Thread.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;sleep&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;300&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;catch&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (InterruptedException &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;Thread.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;currentThread&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;interrupt&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;finally&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;emVoo.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;decrementAndGet&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;limite.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;release&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;();         &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// sem isto, o limite vaza até zerar&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;boolean&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;entrar&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;try&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; limite.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;tryAcquire&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;200&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, TimeUnit.MILLISECONDS);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;catch&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (InterruptedException &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;Thread.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;currentThread&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;interrupt&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;main&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;[] &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;args&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;try&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (ExecutorService executor &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; Executors.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;newVirtualThreadPerTaskExecutor&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;()) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;IntStream.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;range&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;1000&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;forEach&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(i &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; executor.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;submit&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(BulkheadSimples&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;capturar));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;System.out.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;pico de chamadas simultâneas: &quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; pico.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;());&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;System.out.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;recusadas por você:           &quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; recusadas.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;());&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;Saída&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#e1e4e8;--1:#24292e&quot;&gt;pico de chamadas simultâneas: 100&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#e1e4e8;--1:#24292e&quot;&gt;recusadas por você:           900&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;O pico nunca passa de 100, por mais requisições que cheguem. As 100 primeiras entram; as outras 900 esperam 200 ms por uma vaga, e nenhuma vaga abre antes dos 300 ms da chamada, então são recusadas. O &lt;code&gt;finally&lt;/code&gt; é o ponto crítico do código: se a permissão não for devolvida em todo caminho de saída, inclusive em exceção, o limite encolhe sozinho até travar tudo.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;De onde vem o número.&lt;/strong&gt; Não é chute nem é o contrato do parceiro (o contrato é o teto, não a meta). Vem da &lt;a href=&quot;https://en.wikipedia.org/wiki/Little%27s_law&quot;&gt;lei de Little&lt;/a&gt;: chamadas em andamento = vazão × tempo médio de resposta. Cem chamadas por segundo com resposta em 300 ms dão 30 chamadas em andamento, em média. Some uma folga para picos e meça. O 100 dos exemplos é só ilustrativo.&lt;/p&gt;
&lt;h3 id=&quot;circuit-breaker--com-resilience4j&quot;&gt;Circuit breaker — com Resilience4j&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#circuit-breaker--com-resilience4j&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Aqui entra dependência. No Maven:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;pom.xml&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;xml&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#85E89D;--1:#1E7734&quot;&gt;dependency&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#85E89D;--1:#1E7734&quot;&gt;groupId&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&gt;io.github.resilience4j&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#85E89D;--1:#1E7734&quot;&gt;groupId&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#85E89D;--1:#1E7734&quot;&gt;artifactId&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&gt;resilience4j-circuitbreaker&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#85E89D;--1:#1E7734&quot;&gt;artifactId&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#85E89D;--1:#1E7734&quot;&gt;version&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&gt;2.4.0&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#85E89D;--1:#1E7734&quot;&gt;version&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#85E89D;--1:#1E7734&quot;&gt;dependency&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;O exemplo abaixo simula um parceiro que falha por um tempo e depois volta, e imprime cada mudança de estado:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;Breaker.java&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; io.github.resilience4j.circuitbreaker.CallNotPermittedException;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; io.github.resilience4j.circuitbreaker.CircuitBreaker;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; io.github.resilience4j.circuitbreaker.CircuitBreakerConfig;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; java.time.Duration;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;Breaker&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;volatile&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;boolean&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; parceiroFora &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; String &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;capturar&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (parceiroFora) &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;throw&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;RuntimeException&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;adquirente indisponível&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;CAPTURADO&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;main&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;[] &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;args&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;throws&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; Exception {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;CircuitBreakerConfig config &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; CircuitBreakerConfig.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;custom&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;slidingWindowType&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(CircuitBreakerConfig.SlidingWindowType.COUNT_BASED)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;slidingWindowSize&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;20&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;)                        &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// olha as últimas 20 chamadas&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;minimumNumberOfCalls&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;)                     &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// só decide depois de 10&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;failureRateThreshold&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;50&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;)                     &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// abre com 50% de falha&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;waitDurationInOpenState&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(Duration.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;ofSeconds&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;permittedNumberOfCallsInHalfOpenState&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;)     &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// sondagem ao voltar&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;build&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;CircuitBreaker breaker &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; CircuitBreaker.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;adquirente&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, config);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;breaker.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;getEventPublisher&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;               &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;onStateTransition&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(e &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; System.out.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;&gt;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; e.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;getStateTransition&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;()));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; i &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;; i &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;&amp;#x3C;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;60&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;; i&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (i &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;40&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) parceiroFora &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;;  &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// parceiro se recupera&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;try&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;String resposta &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; breaker.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;executeSupplier&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(Breaker&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;capturar);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;System.out.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(i &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;: &quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; resposta);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;catch&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (CallNotPermittedException &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;System.out.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(i &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;: barrado pelo breaker, sem sair da aplicação&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;catch&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (RuntimeException &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;System.out.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(i &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;: falhou no parceiro&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;Thread.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;sleep&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;150&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Para rodar sem Maven, basta pôr no classpath os JARs &lt;code&gt;resilience4j-circuitbreaker&lt;/code&gt;, &lt;code&gt;resilience4j-core&lt;/code&gt; e &lt;code&gt;slf4j-api&lt;/code&gt; (&lt;code&gt;java -cp &quot;lib/*&quot; Breaker.java&lt;/code&gt;). A saída, resumida (o SLF4J imprime antes um aviso de que não há logger configurado, que pode ser ignorado):&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;Saída (resumida)&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#e1e4e8;--1:#24292e&quot;&gt;1: falhou no parceiro&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#e1e4e8;--1:#24292e&quot;&gt;...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#e1e4e8;--1:#24292e&quot;&gt;9: falhou no parceiro&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#e1e4e8;--1:#24292e&quot;&gt;&gt;&gt; State transition from CLOSED to OPEN&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#e1e4e8;--1:#24292e&quot;&gt;10: falhou no parceiro&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#e1e4e8;--1:#24292e&quot;&gt;11: barrado pelo breaker, sem sair da aplicação&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#e1e4e8;--1:#24292e&quot;&gt;...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#e1e4e8;--1:#24292e&quot;&gt;29: barrado pelo breaker, sem sair da aplicação&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#e1e4e8;--1:#24292e&quot;&gt;&gt;&gt; State transition from OPEN to HALF_OPEN&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#e1e4e8;--1:#24292e&quot;&gt;30: falhou no parceiro&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#e1e4e8;--1:#24292e&quot;&gt;31: falhou no parceiro&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#e1e4e8;--1:#24292e&quot;&gt;&gt;&gt; State transition from HALF_OPEN to OPEN&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#e1e4e8;--1:#24292e&quot;&gt;32: falhou no parceiro&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#e1e4e8;--1:#24292e&quot;&gt;33: barrado pelo breaker, sem sair da aplicação&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#e1e4e8;--1:#24292e&quot;&gt;...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#e1e4e8;--1:#24292e&quot;&gt;51: barrado pelo breaker, sem sair da aplicação&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#e1e4e8;--1:#24292e&quot;&gt;&gt;&gt; State transition from OPEN to HALF_OPEN&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#e1e4e8;--1:#24292e&quot;&gt;52: CAPTURADO&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#e1e4e8;--1:#24292e&quot;&gt;53: CAPTURADO&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#e1e4e8;--1:#24292e&quot;&gt;&gt;&gt; State transition from HALF_OPEN to CLOSED&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#e1e4e8;--1:#24292e&quot;&gt;54: CAPTURADO&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#e1e4e8;--1:#24292e&quot;&gt;...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#e1e4e8;--1:#24292e&quot;&gt;60: CAPTURADO&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;A sequência inteira aparece:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;As 10 primeiras chamadas falham de verdade. Na décima, a taxa de falha chega a 100% e o breaker abre. A linha &lt;code&gt;&gt;&gt;&lt;/code&gt; sai antes de &lt;code&gt;10: falhou&lt;/code&gt; porque o evento dispara quando o breaker registra a falha, antes de a exceção chegar ao &lt;code&gt;catch&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Durante 3 segundos (cerca de 20 voltas de 150 ms), as chamadas são barradas sem sair da aplicação.&lt;/li&gt;
&lt;li&gt;Na primeira chamada depois desse tempo, o breaker passa a meio-aberto e deixa 3 chamadas passarem para sondar. O parceiro ainda está fora, então ele abre de novo.&lt;/li&gt;
&lt;li&gt;O parceiro volta na chamada 40, mas o breaker só descobre na sondagem seguinte, na 52. As 3 chamadas de sondagem dão certo e o breaker fecha.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Os três estados: &lt;strong&gt;fechado&lt;/strong&gt; é o saudável, com a corrente passando (o nome confunde no começo); &lt;strong&gt;aberto&lt;/strong&gt; é o disjuntor desarmado, com falha imediata e sem tráfego; &lt;strong&gt;meio-aberto&lt;/strong&gt; deixa poucas chamadas passarem para sondar e decide se fecha ou abre de novo.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;De onde vem, e o que ele não é.&lt;/strong&gt; O circuit breaker não tem relação com virtual threads. Ele é bem mais antigo: aparece no livro &lt;em&gt;Release It!&lt;/em&gt;, de Michael Nygard, de 2007, e ficou conhecido com o Hystrix, que a Netflix abriu em 2012, mais de dez anos antes das virtual threads. O problema que ele resolve é de sistema distribuído: parar de insistir com um serviço que está mal. Vale em qualquer linguagem, com ou sem threads, síncrono ou assíncrono. O mesmo vale para o bulkhead, que vem do mesmo livro.&lt;/p&gt;
&lt;p&gt;A relação com este caso é outra, e vale guardar assim: &lt;strong&gt;virtual threads não criaram a necessidade, tiraram o disfarce.&lt;/strong&gt; O pool de 200 threads dava um limite acidental de graça, e esse limite mascarava a ausência das duas proteções. Ao remover o pool, o que estava escondido apareceu.&lt;/p&gt;
&lt;p&gt;Isso importa na hora de aplicar. Quem conclui que “circuit breaker é coisa de virtual thread” deixa de usá-lo nos serviços que continuam com pool, e lá ele é igualmente necessário; só que a falha demora mais a aparecer.&lt;/p&gt;
&lt;h3 id=&quot;em-produção-com-spring-boot&quot;&gt;Em produção, com Spring Boot&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#em-produção-com-spring-boot&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;No Spring Boot, o mesmo vira configuração. O starter do Resilience4j exige o AOP e o Actuator do Spring Boot:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;pom.xml&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;xml&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#85E89D;--1:#1E7734&quot;&gt;dependency&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#85E89D;--1:#1E7734&quot;&gt;groupId&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&gt;io.github.resilience4j&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#85E89D;--1:#1E7734&quot;&gt;groupId&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#85E89D;--1:#1E7734&quot;&gt;artifactId&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&gt;resilience4j-spring-boot3&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#85E89D;--1:#1E7734&quot;&gt;artifactId&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#85E89D;--1:#1E7734&quot;&gt;version&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&gt;2.4.0&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#85E89D;--1:#1E7734&quot;&gt;version&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#85E89D;--1:#1E7734&quot;&gt;dependency&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#85E89D;--1:#1E7734&quot;&gt;dependency&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#85E89D;--1:#1E7734&quot;&gt;groupId&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&gt;org.springframework.boot&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#85E89D;--1:#1E7734&quot;&gt;groupId&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#85E89D;--1:#1E7734&quot;&gt;artifactId&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&gt;spring-boot-starter-aop&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#85E89D;--1:#1E7734&quot;&gt;artifactId&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#85E89D;--1:#1E7734&quot;&gt;dependency&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#85E89D;--1:#1E7734&quot;&gt;dependency&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#85E89D;--1:#1E7734&quot;&gt;groupId&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&gt;org.springframework.boot&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#85E89D;--1:#1E7734&quot;&gt;groupId&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#85E89D;--1:#1E7734&quot;&gt;artifactId&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&gt;spring-boot-starter-actuator&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#85E89D;--1:#1E7734&quot;&gt;artifactId&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#85E89D;--1:#1E7734&quot;&gt;dependency&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;application.yml&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;yaml&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#85E89D;--1:#1E7734&quot;&gt;resilience4j&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#85E89D;--1:#1E7734&quot;&gt;bulkhead&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#85E89D;--1:#1E7734&quot;&gt;instances&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#85E89D;--1:#1E7734&quot;&gt;adquirente&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#85E89D;--1:#1E7734&quot;&gt;maxConcurrentCalls&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;100&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#85E89D;--1:#1E7734&quot;&gt;maxWaitDuration&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;200ms&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#85E89D;--1:#1E7734&quot;&gt;circuitbreaker&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#85E89D;--1:#1E7734&quot;&gt;instances&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#85E89D;--1:#1E7734&quot;&gt;adquirente&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#85E89D;--1:#1E7734&quot;&gt;slidingWindowType&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;COUNT_BASED&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#85E89D;--1:#1E7734&quot;&gt;slidingWindowSize&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;20&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#85E89D;--1:#1E7734&quot;&gt;minimumNumberOfCalls&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;10&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#85E89D;--1:#1E7734&quot;&gt;failureRateThreshold&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;50&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#85E89D;--1:#1E7734&quot;&gt;waitDurationInOpenState&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;3s&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#85E89D;--1:#1E7734&quot;&gt;permittedNumberOfCallsInHalfOpenState&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;3&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;Bulkhead&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;adquirente&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;CircuitBreaker&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;adquirente&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;fallbackMethod&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;indisponivel&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; Resposta &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;capturar&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(Cobranca cobranca) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; adquirenteClient.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;capturar&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(cobranca);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// mesma assinatura do método protegido, mais a exceção no final&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; Resposta &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;indisponivel&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(Cobranca cobranca, Throwable causa) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; Resposta.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;negada&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;INDISPONIVEL_TEMPORARIAMENTE&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Com o Actuator, as métricas do bulkhead e do breaker saem pelo Micrometer, e dali para o Prometheus, o Dynatrace ou a ferramenta de observabilidade do time.&lt;/p&gt;
&lt;p&gt;Cinco detalhes que costumam morder:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Use o bulkhead de semáforo, não o de thread pool.&lt;/strong&gt; O Resilience4j tem as duas variantes, e a de thread pool reintroduz exatamente o pool que você acabou de tirar. &lt;code&gt;@Bulkhead&lt;/code&gt; sem &lt;code&gt;type&lt;/code&gt; já usa o de semáforo.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;As anotações só funcionam através do proxy do Spring.&lt;/strong&gt; Se outro método da mesma classe chama &lt;code&gt;capturar()&lt;/code&gt; direto, o bulkhead e o breaker não rodam. O motivo está em &lt;a href=&quot;https://cesarschutz.com.br/posts/aop-jdk-proxy-cglib/#a-pegadinha-da-self-invocation&quot;&gt;A pegadinha da self-invocation&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Timeout é pré-requisito.&lt;/strong&gt; Sem tempo limite na chamada HTTP, ela não falha: fica pendurada. Uma chamada que nunca termina nunca entra na conta do breaker, que então não abre, e as conexões esperando se acumulam.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;O limiar é proporção, não contagem.&lt;/strong&gt; Baixo demais, o breaker abre por qualquer soluço; alto demais, nunca abre. E o &lt;code&gt;minimumNumberOfCalls&lt;/code&gt; evita que três falhas às três da manhã, com tráfego baixo, abram o disjuntor.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cuidado com a ordem dos aspectos.&lt;/strong&gt; Por padrão, o Resilience4j aplica, de fora para dentro: Retry, CircuitBreaker, RateLimiter, TimeLimiter, Bulkhead (a ordem pode ser mudada por propriedades como &lt;code&gt;resilience4j.retry.retryAspectOrder&lt;/code&gt;). Sendo o mais externo, o retry repete o conjunto inteiro. Por isso ele precisa de espera crescente com um pouco de aleatoriedade (&lt;a href=&quot;https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/&quot;&gt;backoff exponencial com jitter&lt;/a&gt;), ou você cria uma tempestade de retries que derruba de vez quem já estava mal. Em cobrança, retry também exige idempotência: veja &lt;a href=&quot;https://cesarschutz.com.br/posts/cobranca-duplicada-no-retry/&quot;&gt;Cobrança duplicada no retry&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;o-que-devolver-para-quem-foi-recusado&quot;&gt;O que devolver para quem foi recusado&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#o-que-devolver-para-quem-foi-recusado&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Em cartão, &lt;strong&gt;negar não é falhar&lt;/strong&gt;. Um erro genérico obriga a maquininha a decidir sem informação. Uma negativa com um código de indisponibilidade temporária diz que o problema é passageiro, e não uma recusa por saldo ou por suspeita de fraude. Quem recebe pode tentar de novo depois, e quem atende o portador (o titular do cartão) sabe o que aconteceu.&lt;/p&gt;
&lt;p&gt;O critério para escolher entre recusa imediata e nova tentativa é o orçamento de tempo. Uma autorização síncrona tem poucos segundos, então recusar rápido é o caminho principal. Retentar fica para os fluxos assíncronos, como ajuste financeiro, estorno e processamento em lote, onde a espera cabe.&lt;/p&gt;
&lt;h2 id=&quot;8-padrões-nomeados&quot;&gt;8. Padrões nomeados&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#8-padrões-nomeados&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Já explicados acima — aqui fica só o nome formal&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Carrier pinning&lt;/strong&gt; — a virtual thread bloqueia sem conseguir desmontar e mantém a carrier refém. Por &lt;code&gt;synchronized&lt;/code&gt;, só do Java 21 ao 23. &lt;em&gt;Onde mais aparece:&lt;/em&gt; mesmo no Java 24 em diante, ainda há pinning quando código nativo chama de volta código Java que bloqueia, e durante o carregamento e a inicialização de classes (&lt;a href=&quot;https://openjdk.org/jeps/491&quot;&gt;JEP 491&lt;/a&gt;). O Java 26 tirou um desses casos, a espera pela inicialização de uma classe (&lt;a href=&quot;https://cesarschutz.com.br/posts/java-29/#virtual-threads-liberam-a-carrier-enquanto-esperam-a-inicializa%C3%A7%C3%A3o-de-uma-classe&quot;&gt;post do Java 29&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CLOSE_WAIT como sintoma&lt;/strong&gt; — socket que o outro lado fechou e o seu não. &lt;em&gt;Onde mais aparece:&lt;/em&gt; vazamento de conexão por &lt;code&gt;close()&lt;/code&gt; que não roda, cliente HTTP sem try-with-resources, pool que nunca devolve a conexão. É um dos primeiros lugares a olhar quando o processo está vivo, mas mudo.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deslocamento de gargalo&lt;/strong&gt; — remover um limite não aumenta a capacidade, só empurra a fila para o próximo recurso escasso. &lt;em&gt;Onde mais aparece:&lt;/em&gt; aumentar o pool de threads e derrubar o banco, subir réplicas e saturar a rede, paralelizar um job e estourar a cota de uma API de terceiro.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bulkhead&lt;/strong&gt; — limite declarado de chamadas simultâneas a um recurso, para que a sobrecarga de uma dependência não afunde o serviço inteiro. O nome vem das anteparas que dividem o casco de um navio em compartimentos estanques. Vem do livro &lt;em&gt;Release It!&lt;/em&gt;, de Michael Nygard (2007), e não tem nada a ver com virtual threads. &lt;em&gt;Onde mais aparece:&lt;/em&gt; pool de conexões separado por dependência, limite de consumidores por tópico, isolamento de clientes (&lt;em&gt;tenants&lt;/em&gt;) em SaaS.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Circuit breaker&lt;/strong&gt; — para de chamar quem está falhando, espera e volta sondando. Três estados: fechado, aberto e meio-aberto. Também vem do &lt;em&gt;Release It!&lt;/em&gt; (2007) e foi popularizado pelo Hystrix, da Netflix, em 2012, anos antes das virtual threads. &lt;em&gt;Onde mais aparece:&lt;/em&gt; em qualquer chamada a terceiro, e também entre microsserviços internos. &lt;strong&gt;Virtual threads não criaram a necessidade dele nem do bulkhead, só tiraram o disfarce&lt;/strong&gt;, porque o pool de threads dava um limite acidental que mascarava a ausência dos dois.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Mencionados de passagem — vale saber o que são&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Backpressure&lt;/strong&gt; — mecanismo pelo qual quem está sobrecarregado sinaliza a quem produz que desacelere, em vez de aceitar tudo e desmoronar. Semáforo, fila limitada e rate limit são formas de aplicar. &lt;em&gt;Por que importa aqui:&lt;/em&gt; virtual threads não aplicam backpressure sozinhas, elas aceitam tudo o que chega. O freio precisa ser declarado, como o semáforo do bulkhead.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scoped Values&lt;/strong&gt; — alternativa ao &lt;code&gt;ThreadLocal&lt;/code&gt; para compartilhar dados imutáveis ao longo de uma chamada, finalizada no Java 25 (&lt;a href=&quot;https://openjdk.org/jeps/506&quot;&gt;JEP 506&lt;/a&gt;; detalhes no &lt;a href=&quot;https://cesarschutz.com.br/posts/java-25/#scoped-values&quot;&gt;post do Java 25&lt;/a&gt;). Virtual threads não devem ser reaproveitadas em pool, então o velho hábito de guardar um objeto caro por thread vira um objeto por requisição. Como elas podem ser muitas, a JEP 444 pede cuidado com &lt;code&gt;ThreadLocal&lt;/code&gt;: o consumo de memória só aparece sob carga alta. &lt;em&gt;Onde mais aparece:&lt;/em&gt; propagação de contexto, como usuário autenticado, trace id e tenant.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;JEP&lt;/strong&gt; — JDK Enhancement Proposal, o documento que descreve cada mudança da plataforma e o raciocínio por trás dela. A JEP 444 trouxe as virtual threads no Java 21; a JEP 491 corrigiu o pinning por &lt;code&gt;synchronized&lt;/code&gt; no Java 24. &lt;em&gt;Por que está aqui:&lt;/em&gt; ler a JEP é a forma de conferir o que uma versão mudou sem depender de post de blog.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;9-onde-eu-apertaria-numa-entrevista&quot;&gt;9. Onde eu apertaria numa entrevista&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#9-onde-eu-apertaria-numa-entrevista&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;O upgrade para o Java 25 leva semanas. O que você faz hoje, no plantão?&lt;/li&gt;
&lt;li&gt;Java 25 e Spring Boot 4 no mesmo deploy: se algo quebrar, como você sabe qual dos dois foi?&lt;/li&gt;
&lt;li&gt;Qual número você coloca no semáforo do adquirente, e como chega nele?&lt;/li&gt;
&lt;li&gt;Depois de tudo corrigido, que métrica no Dynatrace avisaria que o pinning voltou?&lt;/li&gt;
&lt;li&gt;O teste de carga passou limpo. O que faltava nele?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;fontes&quot;&gt;Fontes&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#fontes&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;OpenJDK — &lt;a href=&quot;https://openjdk.org/jeps/444&quot;&gt;JEP 444: Virtual Threads&lt;/a&gt; (casos de pinning, carriers, thread dump, JFR, &lt;code&gt;ThreadLocal&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;OpenJDK — &lt;a href=&quot;https://openjdk.org/jeps/491&quot;&gt;JEP 491: Synchronize Virtual Threads without Pinning&lt;/a&gt; (Java 24)&lt;/li&gt;
&lt;li&gt;OpenJDK — &lt;a href=&quot;https://openjdk.org/jeps/506&quot;&gt;JEP 506: Scoped Values&lt;/a&gt; (Java 25)&lt;/li&gt;
&lt;li&gt;Oracle — &lt;a href=&quot;https://docs.oracle.com/en/java/javase/21/core/virtual-threads.html&quot;&gt;Virtual Threads&lt;/a&gt; (guia do Java 21)&lt;/li&gt;
&lt;li&gt;Oracle — &lt;a href=&quot;https://docs.oracle.com/en/java/javase/21/docs/specs/man/java.html&quot;&gt;The java Command&lt;/a&gt; (tamanho padrão da pilha, &lt;code&gt;-Xss&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Netflix Technology Blog — &lt;a href=&quot;https://netflixtechblog.com/java-21-virtual-threads-dude-wheres-my-lock-3052540e231d&quot;&gt;Java 21 Virtual Threads: Dude, Where’s My Lock?&lt;/a&gt; (julho de 2024)&lt;/li&gt;
&lt;li&gt;InfoQ — &lt;a href=&quot;https://www.infoq.com/articles/virtual-threads-after-jdk24/&quot;&gt;Virtual Threads after JDK 24: What Changed for Production Java&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;IETF — &lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc9293&quot;&gt;RFC 9293: Transmission Control Protocol&lt;/a&gt; (estados TCP, CLOSE-WAIT)&lt;/li&gt;
&lt;li&gt;Spring Boot — &lt;a href=&quot;https://docs.spring.io/spring-boot/appendix/application-properties/index.html&quot;&gt;Common Application Properties&lt;/a&gt; (&lt;code&gt;spring.threads.virtual.enabled&lt;/code&gt;, &lt;code&gt;server.tomcat.threads.max&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Spring Boot — &lt;a href=&quot;https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.2-Release-Notes&quot;&gt;Spring Boot 3.2 Release Notes&lt;/a&gt; (suporte a virtual threads)&lt;/li&gt;
&lt;li&gt;HikariCP — &lt;a href=&quot;https://github.com/brettwooldridge/HikariCP&quot;&gt;README&lt;/a&gt; (&lt;code&gt;maximumPoolSize&lt;/code&gt; e &lt;code&gt;connectionTimeout&lt;/code&gt; padrão)&lt;/li&gt;
&lt;li&gt;Resilience4j — &lt;a href=&quot;https://resilience4j.readme.io/docs/circuitbreaker&quot;&gt;CircuitBreaker&lt;/a&gt;, &lt;a href=&quot;https://resilience4j.readme.io/docs/bulkhead&quot;&gt;Bulkhead&lt;/a&gt; e &lt;a href=&quot;https://resilience4j.readme.io/docs/getting-started-3&quot;&gt;Getting Started com Spring Boot 3&lt;/a&gt; (dependências, ordem dos aspectos, fallback)&lt;/li&gt;
&lt;li&gt;Martin Fowler — &lt;a href=&quot;https://martinfowler.com/bliki/CircuitBreaker.html&quot;&gt;CircuitBreaker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;ACM Digital Library — &lt;a href=&quot;https://dl.acm.org/doi/10.5555/1200767&quot;&gt;Release It!: Design and Deploy Production-Ready Software&lt;/a&gt; (Michael T. Nygard, 2007)&lt;/li&gt;
&lt;li&gt;Netflix Technology Blog — &lt;a href=&quot;https://netflixtechblog.com/introducing-hystrix-for-resilience-engineering-13531c1ab362&quot;&gt;Introducing Hystrix for Resilience Engineering&lt;/a&gt; (novembro de 2012)&lt;/li&gt;
&lt;li&gt;Wikipedia — &lt;a href=&quot;https://en.wikipedia.org/wiki/Little%27s_law&quot;&gt;Little’s law&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS Architecture Blog — &lt;a href=&quot;https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/&quot;&gt;Exponential Backoff And Jitter&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>Java</category><category>Virtual Threads</category><category>Concorrência</category><category>JVM</category></item><item><title>Efeito externo sem registro local — a cobrança passou e o banco não gravou</title><link>https://cesarschutz.com.br/posts/efeito-externo-sem-registro-local/</link><guid isPermaLink="true">https://cesarschutz.com.br/posts/efeito-externo-sem-registro-local/</guid><description>A captura no adquirente passa e a gravação no seu banco falha: grave a intenção antes de causar o efeito. Escrita dupla, outbox e relay, conciliação, CDC, event sourcing e por que o 2PC fica de fora.</description><pubDate>Fri, 11 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Seu serviço cobrou o cliente no &lt;strong&gt;adquirente&lt;/strong&gt; (a empresa que processa a transação de cartão), mas o processo morreu antes de gravar a cobrança no banco. O dinheiro saiu e você não tem registro disso. Este post mostra por que retry e alerta não resolvem, e qual desenho garante que todo efeito externo deixa rastro local: gravar a intenção antes de agir, com tabela outbox, relay e conciliação. É a continuação de &lt;a href=&quot;https://cesarschutz.com.br/posts/cobranca-duplicada-no-retry/&quot;&gt;Cobrança duplicada no retry&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Formato do artigo: um cenário real, a primeira resposta que costuma aparecer, onde ela falha e o que fica de aprendizado.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;1-desafio&quot;&gt;1. Desafio&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#1-desafio&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A chave de idempotência está implantada e funcionando. Um dia, o gráfico mostra cobranças que aparecem na fatura do cliente, mas não existem no seu banco.&lt;/p&gt;
&lt;p&gt;Investigando, o fluxo é este: o serviço chama o adquirente, a &lt;strong&gt;captura&lt;/strong&gt; (a efetivação da cobrança) passa, e só depois o serviço grava a cobrança no Postgres. Entre as duas coisas, o processo morreu.&lt;/p&gt;
&lt;p&gt;Como você desenha isso para que nunca exista dinheiro cobrado sem registro?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;O que o cenário não diz, e vale perguntar:&lt;/strong&gt; com que frequência isso acontece, se o adquirente permite consultar o status depois e quanto tempo o cliente aceita esperar pela resposta.&lt;/p&gt;
&lt;h2 id=&quot;2-a-primeira-resposta&quot;&gt;2. A primeira resposta&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#2-a-primeira-resposta&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Envolvo a chamada em try/catch. Se a gravação falhar, faço retry algumas vezes; se ainda assim falhar, registro no log e disparo um alerta para o time olhar.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;3-onde-furou&quot;&gt;3. Onde furou&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#3-onde-furou&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Retry e alerta tratam o sintoma depois que o dano já existe. Nenhum dos dois muda o fato estrutural: o efeito externo aconteceu antes de existir qualquer registro local.&lt;/p&gt;
&lt;p&gt;E se o processo morre de verdade, não há try/catch que rode: o bloco de tratamento morre junto. Isso acontece quando o contêiner é encerrado à força (SIGKILL), seja por falta de memória (OOM), seja num deploy que estoura o prazo de desligamento. O post &lt;a href=&quot;https://cesarschutz.com.br/posts/sigterm-sigkill-kubernetes/&quot;&gt;SIGTERM e SIGKILL&lt;/a&gt; detalha esse ciclo no Kubernetes.&lt;/p&gt;
&lt;p&gt;O detalhe mais desconfortável: a chave de idempotência do post sobre &lt;a href=&quot;https://cesarschutz.com.br/posts/cobranca-duplicada-no-retry/&quot;&gt;cobrança duplicada no retry&lt;/a&gt; não protege aqui. Ela só existiria dentro da linha que não chegou a ser gravada, então o retry seguinte chega sem nada para comparar e captura de novo.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cesarschutz.com.br/posts/efeito-externo-sem-registro-local/efeito-externo-sem-registro.svg&quot; alt=&quot;Diagrama: o serviço captura no adquirente, o processo morre antes do INSERT, não sobra registro local e o retry cobra de novo&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;4-aprendizado-o-problema-da-escrita-dupla&quot;&gt;4. Aprendizado: o problema da escrita dupla&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#4-aprendizado-o-problema-da-escrita-dupla&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Escrever em dois sistemas que não compartilham transação é a &lt;strong&gt;escrita dupla&lt;/strong&gt; (&lt;em&gt;dual write&lt;/em&gt;). Seu banco não sabe nada sobre o adquirente, e não existe commit que cubra os dois. Uma falha entre as duas escritas deixa os dois lados discordando.&lt;/p&gt;
&lt;p&gt;O que não resolve, mesmo parecendo que resolve:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Inverter a ordem&lt;/strong&gt;: gravar a cobrança como concluída e só depois chamar o adquirente troca o problema de lado. Em vez de cobrança sem registro, você passa a ter registro sem cobrança.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Retry no catch&lt;/strong&gt;: só roda se o processo continuar vivo. E, quando a falha é ambígua (um timeout, por exemplo), ela não diz se a operação aconteceu; repetir às cegas pode transformar perda em duplicidade.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Transação distribuída com 2PC&lt;/strong&gt; (&lt;em&gt;two-phase commit&lt;/em&gt;, explicado na seção 5): a API do adquirente não participa desse protocolo. E, mesmo entre sistemas que participam, os recursos ficam travados enquanto o coordenador não decide, e uma falha do coordenador deixa todos bloqueados.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;O que resolve é mudar o que se escreve primeiro: &lt;strong&gt;grave a intenção antes de causar o efeito.&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Numa única transação do Postgres, o serviço grava a cobrança com status PENDENTE e, na &lt;strong&gt;tabela outbox&lt;/strong&gt; (uma tabela de eventos a publicar), o evento &lt;code&gt;CobrancaIniciada&lt;/code&gt;. Ou as duas linhas existem, ou nenhuma.&lt;/li&gt;
&lt;li&gt;Só depois do commit ele chama o adquirente, enviando a mesma chave de idempotência, se o adquirente aceitar uma (a API da Stripe, por exemplo, aceita o cabeçalho &lt;code&gt;Idempotency-Key&lt;/code&gt;). Assim, repetir a captura é seguro.&lt;/li&gt;
&lt;li&gt;Com a resposta, atualiza a linha para CAPTURADO e grava o evento &lt;code&gt;CobrancaCapturada&lt;/code&gt; no outbox, também numa transação só.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Se o processo cair no meio do caminho, sobra um PENDENTE contando exatamente o que faltou terminar. E o retry do cliente agora esbarra numa linha que existe: em vez de capturar às cegas, o serviço sabe que precisa descobrir o que aconteceu com aquela chave.&lt;/p&gt;
&lt;p&gt;Duas peças completam o desenho:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Relay do outbox&lt;/strong&gt;: um processo separado lê a tabela outbox, publica os eventos no broker de mensagens e os marca como enviados. Se cair no meio, publica de novo, então a entrega é &lt;strong&gt;pelo menos uma vez&lt;/strong&gt; e quem consome precisa ser idempotente.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Conciliação&lt;/strong&gt;: um job varre os PENDENTE antigos e pergunta o status ao adquirente. Se a captura passou, atualiza a linha; se não passou, marca como falha ou tenta de novo com a mesma chave. É a rede que pega o que escapou.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://cesarschutz.com.br/posts/efeito-externo-sem-registro-local/grave-intencao-antes-de-agir.svg&quot; alt=&quot;Diagrama: a cobrança PENDENTE e o evento do outbox são gravados na mesma transação antes da captura; relay e conciliação rodam fora do request&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;5-padrões-nomeados&quot;&gt;5. Padrões nomeados&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#5-padrões-nomeados&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Já explicados acima; aqui fica só o nome formal&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Dual write problem&lt;/strong&gt;: uma operação lógica que precisa escrever em dois sistemas sem transação comum; qualquer falha no meio deixa os dois discordando. &lt;em&gt;Onde mais aparece:&lt;/em&gt; banco mais fila, banco mais cache, banco mais índice de busca, banco mais API de terceiro. É a mesma forma em todos.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Transactional outbox&lt;/strong&gt;: dado e evento gravados na mesma transação; a entrega do evento vira um passo separado e repetível. &lt;em&gt;Onde mais aparece:&lt;/em&gt; qualquer serviço que precisa avisar outro depois de mudar o próprio estado, como no post sobre &lt;a href=&quot;https://cesarschutz.com.br/posts/w3c-trace-context/&quot;&gt;W3C Trace Context&lt;/a&gt;, em que o &lt;code&gt;traceparent&lt;/code&gt; viaja pelo outbox.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Intenção gravada antes do efeito (&lt;em&gt;pending state&lt;/em&gt;)&lt;/strong&gt;: registrar a intenção antes de causar o efeito, para que a falha deixe rastro em vez de silêncio. É um nome descritivo, não um padrão de catálogo; o artigo de Brandur Leach sobre chaves de idempotência formaliza a mesma ideia como fases atômicas com pontos de recuperação. &lt;em&gt;Onde mais aparece:&lt;/em&gt; upload em duas etapas, emissão de nota fiscal, provisionamento de recurso em nuvem. É o princípio do &lt;em&gt;write-ahead log&lt;/em&gt; do banco (a mudança é registrada no log antes de ser aplicada) levado para o nível da aplicação.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reconciliation (conciliação)&lt;/strong&gt;: comparar periodicamente o seu estado com o do sistema externo e corrigir a diferença. &lt;em&gt;Onde mais aparece:&lt;/em&gt; fechamento contábil, estoque integrado a marketplace, cobrança recorrente. O post &lt;a href=&quot;https://cesarschutz.com.br/posts/arquitetura-de-ledger/&quot;&gt;Arquitetura de ledger&lt;/a&gt; mostra a conciliação aplicada a saldos.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Mencionados de passagem; vale saber o que são&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Change Data Capture (CDC)&lt;/strong&gt;: em vez de um processo consultar a tabela outbox de tempos em tempos (&lt;em&gt;polling&lt;/em&gt;), uma ferramenta lê o log de transações do próprio banco e publica cada mudança quase em tempo real. O Debezium é o nome mais comum. &lt;em&gt;Quando usar no lugar do relay por polling:&lt;/em&gt; quando o atraso do intervalo de consulta não cabe, ou quando o volume torna as consultas caras. &lt;em&gt;O que custa:&lt;/em&gt; mais uma peça de infraestrutura para operar e monitorar. Por isso o polling, que funciona com qualquer banco SQL, costuma ser o ponto de partida.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Event sourcing&lt;/strong&gt;: em vez de guardar o estado atual e emitir eventos, você guarda só a sequência de eventos e calcula o estado a partir dela. Resolve a escrita dupla entre estado e eventos por eliminação: gravar um evento é uma operação só. &lt;em&gt;Atenção:&lt;/em&gt; não elimina a chamada ao adquirente; o efeito externo continua precisando da intenção registrada antes. &lt;em&gt;Quando aparece:&lt;/em&gt; quando o histórico completo é requisito de negócio, o que é comum em domínio financeiro. &lt;em&gt;O que custa:&lt;/em&gt; muda o modelo de dados inteiro e dificulta consultas (em geral exige CQRS), então é decisão de arquitetura, não ajuste pontual.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Two-phase commit (2PC)&lt;/strong&gt;: protocolo em que um coordenador pergunta a todos os participantes se podem confirmar e só então manda confirmar. Existe e funciona entre recursos que o suportam, mas é bloqueante: os participantes seguram travas enquanto esperam a decisão e, se o coordenador falha, ficam presos. E uma API HTTP de terceiro, como a do adquirente, não é participante de 2PC. &lt;em&gt;Por que está aqui:&lt;/em&gt; é a resposta que parece óbvia para quem acabou de conhecer o problema, e saber por que ela é rejeitada vale mais do que saber que ela existe.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;6-onde-eu-apertaria-numa-entrevista&quot;&gt;6. Onde eu apertaria numa entrevista&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#6-onde-eu-apertaria-numa-entrevista&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;O relay parou silenciosamente. Como você descobre antes do cliente?&lt;/li&gt;
&lt;li&gt;Quanto tempo uma cobrança pode ficar PENDENTE antes de virar incidente?&lt;/li&gt;
&lt;li&gt;E se o adquirente responder “não sei” quando a conciliação perguntar?&lt;/li&gt;
&lt;li&gt;A tabela outbox cresce sem parar. Quem limpa, e quando?&lt;/li&gt;
&lt;li&gt;Se a conciliação roda como &lt;a href=&quot;https://cesarschutz.com.br/posts/kubernetes-cronjob-concorrencia/&quot;&gt;CronJob no Kubernetes&lt;/a&gt;, o que acontece quando duas execuções se sobrepõem?&lt;/li&gt;
&lt;li&gt;Vale trocar o relay por CDC no seu caso, ou o polling já resolve?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;fontes&quot;&gt;Fontes&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#fontes&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;AWS Prescriptive Guidance — &lt;a href=&quot;https://docs.aws.amazon.com/prescriptive-guidance/latest/cloud-design-patterns/transactional-outbox.html&quot;&gt;Transactional outbox pattern&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Confluent — &lt;a href=&quot;https://www.confluent.io/blog/dual-write-problem/&quot;&gt;Understanding the Dual-Write Problem&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;microservices.io — &lt;a href=&quot;https://microservices.io/patterns/data/transactional-outbox.html&quot;&gt;Pattern: Transactional outbox&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;microservices.io — &lt;a href=&quot;https://microservices.io/patterns/data/polling-publisher.html&quot;&gt;Pattern: Polling publisher&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;microservices.io — &lt;a href=&quot;https://microservices.io/patterns/data/event-sourcing.html&quot;&gt;Pattern: Event sourcing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Debezium — &lt;a href=&quot;https://debezium.io/blog/2019/02/19/reliable-microservices-data-exchange-with-the-outbox-pattern/&quot;&gt;Reliable Microservices Data Exchange With the Outbox Pattern&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Brandur Leach — &lt;a href=&quot;https://brandur.org/idempotency-keys&quot;&gt;Implementing Stripe-like Idempotency Keys in Postgres&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Stripe — &lt;a href=&quot;https://docs.stripe.com/api/idempotent_requests&quot;&gt;Idempotent requests&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;PostgreSQL — &lt;a href=&quot;https://www.postgresql.org/docs/current/wal-intro.html&quot;&gt;Write-Ahead Logging (WAL)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;PostgreSQL — &lt;a href=&quot;https://www.postgresql.org/docs/current/sql-prepare-transaction.html&quot;&gt;PREPARE TRANSACTION&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Wikipedia — &lt;a href=&quot;https://en.wikipedia.org/wiki/Two-phase_commit_protocol&quot;&gt;Two-phase commit protocol&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Kubernetes — &lt;a href=&quot;https://kubernetes.io/docs/tasks/configure-pod-container/assign-memory-resource/&quot;&gt;Assign Memory Resources to Containers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Kubernetes — &lt;a href=&quot;https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-termination&quot;&gt;Pod Lifecycle: Termination of Pods&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>Arquitetura</category><category>Pagamentos</category><category>Mensageria</category><category>Banco de Dados</category></item><item><title>Cobrança duplicada no retry</title><link>https://cesarschutz.com.br/posts/cobranca-duplicada-no-retry/</link><guid isPermaLink="true">https://cesarschutz.com.br/posts/cobranca-duplicada-no-retry/</guid><description>Por que consultar antes de gravar não impede que um retry cobre o cliente duas vezes, e como resolver com chave de idempotência, restrição única e resposta guardada. Com SQL testado no PostgreSQL.</description><pubDate>Thu, 10 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Um timeout não diz se a operação aconteceu. Quando o app reenvia uma cobrança depois de um timeout, o serviço precisa reconhecer a repetição e não cobrar de novo. Parece simples, mas a solução mais intuitiva, consultar antes de gravar, falha justamente quando o serviço roda em várias instâncias.&lt;/p&gt;
&lt;p&gt;O post segue um roteiro: o cenário, a primeira resposta que costuma aparecer, onde ela falha e a solução que funciona (chave de idempotência, restrição única no banco e resposta guardada), com SQL testado no PostgreSQL 17 e os cuidados de produção.&lt;/p&gt;
&lt;h2 id=&quot;1-o-cenário&quot;&gt;1. O cenário&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#1-o-cenário&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;O app do cliente envia uma requisição de cobrança de R$ 250 para o serviço de autorização. A resposta não chega a tempo e a requisição estoura o timeout. Do lado do cliente, não dá para saber o que aconteceu: o servidor pode ter cobrado, pode ainda estar processando ou pode nem ter recebido o pedido. Então o app reenvia.&lt;/p&gt;
&lt;p&gt;O serviço roda em várias instâncias atrás de um load balancer. O reenvio pode cair numa instância diferente da primeira, e pode chegar enquanto a primeira ainda está trabalhando.&lt;/p&gt;
&lt;p&gt;Como garantir que o cliente seja cobrado uma vez só?&lt;/p&gt;
&lt;p&gt;O nome da propriedade que falta é &lt;strong&gt;idempotência&lt;/strong&gt;: uma operação é idempotente quando repeti-la tem o mesmo efeito que executá-la uma vez. A especificação do HTTP (RFC 9110) classifica GET, PUT e DELETE como idempotentes por definição; POST não é. Uma cobrança é um POST, e cada repetição sem proteção vira uma cobrança nova.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;O que o cenário deixa em aberto de propósito:&lt;/strong&gt; o volume, se o cliente controla o reenvio, por quanto tempo a garantia precisa valer, o que acontece se o reenvio vier no dia seguinte.&lt;/p&gt;
&lt;h2 id=&quot;2-a-primeira-resposta&quot;&gt;2. A primeira resposta&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#2-a-primeira-resposta&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Antes de gravar a cobrança, o serviço consulta a tabela procurando uma cobrança com o mesmo número de pedido. Se já existir, devolve a que existe. Se não existir, insere e captura.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;3-onde-ela-falha&quot;&gt;3. Onde ela falha&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#3-onde-ela-falha&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A ideia está certa: reconhecer o pedido repetido e não cobrar de novo. O problema é &lt;strong&gt;onde&lt;/strong&gt; a verificação acontece.&lt;/p&gt;
&lt;p&gt;Consultar e depois gravar são duas operações separadas, e entre elas existe uma janela, curta, mas real. Se a requisição original e o reenvio caem em instâncias diferentes ao mesmo tempo, as duas consultam antes de qualquer uma gravar, as duas encontram a tabela vazia e as duas cobram.&lt;/p&gt;
&lt;p&gt;Esse defeito tem nome: &lt;strong&gt;condição de corrida do tipo verificar-e-agir&lt;/strong&gt; (&lt;em&gt;check-then-act&lt;/em&gt;). A decisão foi tomada com base num estado que mudou antes da ação.&lt;/p&gt;
&lt;p&gt;Isso dificilmente aparece em teste local, onde as requisições costumam chegar em sequência. Aparece em produção, no pico, quando o volume aumenta a chance de as duas coincidirem. O cenário é fácil de reproduzir no PostgreSQL: duas conexões simultâneas que consultam, esperam um segundo e inserem acabam gravando as duas.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cesarschutz.com.br/posts/cobranca-duplicada-no-retry/retry-cobranca-duplicada.svg&quot; alt=&quot;Diagrama: a requisição original e o reenvio caem em instâncias diferentes, as duas consultam antes de qualquer uma gravar e o cliente é cobrado duas vezes&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;4-a-solução-gravar-primeiro-e-deixar-o-banco-recusar&quot;&gt;4. A solução: gravar primeiro e deixar o banco recusar&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#4-a-solução-gravar-primeiro-e-deixar-o-banco-recusar&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A garantia precisa estar em quem consegue decidir sozinho, sem janela: &lt;strong&gt;o banco&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;São três peças:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Chave de idempotência&lt;/strong&gt;: um identificador que o cliente gera uma vez por intenção de cobrança e repete em todas as tentativas dessa mesma intenção, normalmente num cabeçalho &lt;code&gt;Idempotency-Key&lt;/code&gt;. A Stripe recomenda um UUID v4 ou outro valor aleatório com entropia suficiente para não colidir, e sem dados pessoais. O id do pedido só serve como chave se cada pedido puder ser cobrado uma única vez; se o mesmo pedido pode ter cobranças legítimas separadas, a chave precisa identificar a cobrança, não o pedido.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Restrição única&lt;/strong&gt; (&lt;code&gt;UNIQUE&lt;/code&gt;) no banco sobre essa chave. É ela que transforma “duas gravações” em “uma gravação e uma recusa”.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Resposta guardada&lt;/strong&gt;: a primeira tentativa salva o que respondeu. As seguintes, ao esbarrar na restrição, leem e devolvem exatamente a mesma resposta.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A ordem se inverte: em vez de verificar e depois gravar, você grava e deixa o banco recusar. A janela some porque verificar e gravar passam a ser a mesma operação.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cesarschutz.com.br/posts/cobranca-duplicada-no-retry/idempotencia-solucao.svg&quot; alt=&quot;Diagrama: as duas tentativas carregam a mesma chave; a restrição única deixa só uma inserção passar e a outra devolve a resposta guardada&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;na-prática-com-sql&quot;&gt;Na prática, com SQL&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#na-prática-com-sql&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Uma tabela mínima no PostgreSQL:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://cesarschutz.com.br/_astro/ec.bzl1c.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://cesarschutz.com.br/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;cobranca.sql&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;TABLE&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;cobranca&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;id              &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;bigint&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;GENERATED&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;ALWAYS&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;AS&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;IDENTITY&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;PRIMARY KEY&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;idempotency_key &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;text&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;   &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;NOT NULL&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;pedido_id       &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;bigint&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;NOT NULL&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;valor_centavos  &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;bigint&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;NOT NULL&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;status&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;text&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;   &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;NOT NULL&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;,  &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;-- PROCESSANDO, CAPTURADA ou RECUSADA&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;resposta_http   &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;,              &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;-- status HTTP devolvido na primeira vez&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;resposta_corpo  jsonb,            &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;-- corpo devolvido na primeira vez&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;criada_em       &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;timestamptz&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;NOT NULL&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;DEFAULT&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;now&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;CONSTRAINT&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; uq_cobranca_idempotency_key &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;UNIQUE&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (idempotency_key)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Passo 1: registrar a tentativa antes de cobrar.&lt;/strong&gt; Toda requisição começa tentando inserir a chave, já com o status &lt;code&gt;PROCESSANDO&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;INSERT INTO&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; cobranca (idempotency_key, pedido_id, valor_centavos, &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;status&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;VALUES&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&apos;5b0e7a52-3f1c-4d7e-9a61-2c8f0d4e7b13&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;123&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;25000&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&apos;PROCESSANDO&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;ON&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; CONFLICT (idempotency_key) DO NOTHING&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;RETURNING id;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;O &lt;code&gt;ON CONFLICT ... DO NOTHING&lt;/code&gt; faz o banco ignorar a inserção se a chave já existir, em vez de lançar erro. Como o &lt;code&gt;RETURNING&lt;/code&gt; só devolve linhas de fato inseridas, o resultado responde à pergunta sem janela nenhuma:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;1 linha&lt;/strong&gt;: esta requisição é a primeira. Confirme a transação (&lt;em&gt;commit&lt;/em&gt;), chame o adquirente e grave o resultado (passo 2).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;0 linhas&lt;/strong&gt;: a chave já existia. Não cobre; leia o registro (passo 3).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Sem o &lt;code&gt;ON CONFLICT&lt;/code&gt;, a segunda inserção falha com &lt;code&gt;duplicate key value violates unique constraint &quot;uq_cobranca_idempotency_key&quot;&lt;/code&gt;. Funciona do mesmo jeito, só que a aplicação precisa tratar a exceção.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Passo 2: guardar a resposta&lt;/strong&gt; depois que o adquirente responder:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;UPDATE&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; cobranca&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;   &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;SET&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;status&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;         &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&apos;CAPTURADA&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;       &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;resposta_http  &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;201&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;       &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;resposta_corpo &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&apos;{&quot;cobranca_id&quot;: 1, &quot;status&quot;: &quot;CAPTURADA&quot;}&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; idempotency_key &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&apos;5b0e7a52-3f1c-4d7e-9a61-2c8f0d4e7b13&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Passo 3: responder a uma repetição.&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;status&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, pedido_id, valor_centavos, resposta_http, resposta_corpo&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;FROM&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; cobranca&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; idempotency_key &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&apos;5b0e7a52-3f1c-4d7e-9a61-2c8f0d4e7b13&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Se &lt;code&gt;pedido_id&lt;/code&gt; ou &lt;code&gt;valor_centavos&lt;/code&gt; forem diferentes dos da requisição atual, a chave foi reaproveitada para outra operação. Recuse: o rascunho da IETF para o cabeçalho &lt;code&gt;Idempotency-Key&lt;/code&gt; sugere &lt;code&gt;422 Unprocessable Content&lt;/code&gt;, e a Stripe também devolve erro quando os parâmetros não batem com os da requisição original.&lt;/li&gt;
&lt;li&gt;Se o status for &lt;code&gt;PROCESSANDO&lt;/code&gt;, a primeira tentativa ainda não terminou. Responda &lt;code&gt;409 Conflict&lt;/code&gt; para o cliente tentar de novo mais tarde; é o que o mesmo rascunho propõe.&lt;/li&gt;
&lt;li&gt;Se já houver resposta guardada, devolva &lt;code&gt;resposta_http&lt;/code&gt; e &lt;code&gt;resposta_corpo&lt;/code&gt; como estão.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;cuidados&quot;&gt;Cuidados&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#cuidados&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Confirme o registro antes de chamar o adquirente.&lt;/strong&gt; Se a inserção e a chamada externa ficarem na mesma transação aberta, a segunda inserção com a mesma chave não recusa na hora: o PostgreSQL faz quem tenta inserir esperar até a outra transação terminar. Num teste com PostgreSQL 17, o reenvio ficou parado os dois segundos que a primeira transação levou, e só então recebeu 0 linhas. Sob carga, isso vira conexões presas e fila, e o cliente nunca vê o &lt;code&gt;PROCESSANDO&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Um &lt;code&gt;PROCESSANDO&lt;/code&gt; pode ficar órfão.&lt;/strong&gt; Se o processo morrer entre o commit e a resposta do adquirente, sobra um registro sem desfecho. Descobrir se a cobrança passou é trabalho de conciliação, tema do post &lt;a href=&quot;https://cesarschutz.com.br/posts/efeito-externo-sem-registro-local/&quot;&gt;Efeito externo sem registro local&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Decida por quanto tempo a chave vale.&lt;/strong&gt; A Stripe pode remover chaves com pelo menos 24 horas de idade; uma chave reutilizada depois disso gera uma requisição nova. O rascunho da IETF deixa o prazo para cada API definir e publicar na documentação. Prazo mais longo protege reenvios tardios e custa armazenamento.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Decida se erro também fica guardado.&lt;/strong&gt; A Stripe guarda o status e o corpo da primeira resposta seja sucesso ou falha, inclusive erros &lt;code&gt;500&lt;/code&gt;. Com isso, uma nova tentativa depois de uma recusa exige chave nova, porque é uma nova intenção.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;5-padrões-nomeados&quot;&gt;5. Padrões nomeados&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#5-padrões-nomeados&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Já explicados acima; aqui fica só o nome formal&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Idempotency Key&lt;/strong&gt;: o cliente marca a intenção com um identificador, e o servidor garante que ela produza efeito uma vez só, chegue quantas vezes chegar. &lt;em&gt;Onde mais aparece:&lt;/em&gt; webhooks, APIs públicas de pagamento, comandos consumidos de fila.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Check-then-act race condition&lt;/strong&gt;: verificar um estado e agir com base nele em duas operações separadas; entre uma e outra, o estado muda. Na forma mais geral é catalogada como TOCTOU (&lt;em&gt;time-of-check to time-of-use&lt;/em&gt;, CWE-367). &lt;em&gt;Onde mais aparece:&lt;/em&gt; reserva de estoque, cadastro por e-mail, débito de saldo e o clássico “verifica se o arquivo existe antes de criar”.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Restrição única como mecanismo de concorrência&lt;/strong&gt;: usar a integridade do banco no lugar de coordenação na aplicação. A decisão fica atômica porque acontece dentro da própria escrita. &lt;em&gt;Onde mais aparece:&lt;/em&gt; slug de URL, número de matrícula, qualquer regra do tipo “só pode existir um”.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Mencionados de passagem; vale saber o que são&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Entrega pelo menos uma vez&lt;/strong&gt; (&lt;em&gt;at-least-once delivery&lt;/em&gt;): a mensagem pode chegar repetida, mas não se perde. É a garantia padrão do Kafka, da fila Standard do SQS e do RabbitMQ com confirmações (&lt;em&gt;acks&lt;/em&gt;) na publicação e no consumo, e é o que qualquer retry HTTP produz. “Exatamente uma vez” existe só em escopos limitados, como a deduplicação de 5 minutos das filas FIFO do SQS ou as transações dentro do próprio Kafka; quando o efeito sai para um sistema externo, a documentação do Kafka lembra que o destino precisa cooperar. Na prática, entrega-se pelo menos uma vez e o consumidor é idempotente, o que produz o mesmo efeito final. &lt;em&gt;Onde mais aparece:&lt;/em&gt; toda arquitetura de eventos, e é por isso que idempotência e mensageria andam juntas.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bloqueio pessimista e bloqueio otimista&lt;/strong&gt;: as alternativas à restrição única. No pessimista (&lt;code&gt;SELECT ... FOR UPDATE&lt;/code&gt;), você trava a linha e os concorrentes esperam até você terminar; funciona, mas cria contenção e risco de deadlock sob carga. No otimista, você adiciona uma coluna de versão e só grava se a versão não mudou; quem perde tenta de novo. Os dois precisam de uma linha que já exista. Neste cenário a cobrança ainda não existe, então seria preciso travar outra linha, como a do pedido, o que é mais um motivo para preferir a restrição única. &lt;em&gt;Quando usar no lugar dela:&lt;/em&gt; quando a decisão depende de ler e combinar valores e não cabe numa única chave. &lt;em&gt;Onde mais aparece:&lt;/em&gt; edição concorrente de cadastro, controle de saldo, qualquer “leu, calculou, gravou”. Os dois são detalhados no post &lt;a href=&quot;https://cesarschutz.com.br/posts/bloqueio-otimista-e-pessimista/&quot;&gt;Bloqueio otimista e pessimista&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;6-onde-eu-apertaria-numa-entrevista&quot;&gt;6. Onde eu apertaria numa entrevista&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#6-onde-eu-apertaria-numa-entrevista&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Por quanto tempo a chave vale? Um dia, um mês, para sempre? O que essa escolha custa em armazenamento, e o que acontece com o reenvio que chega depois do prazo?&lt;/li&gt;
&lt;li&gt;Um registro está em &lt;code&gt;PROCESSANDO&lt;/code&gt; há dez minutos. Quem decide se a cobrança passou, e com base em quê?&lt;/li&gt;
&lt;li&gt;E se a captura no adquirente passar, mas a gravação da resposta no banco falhar?&lt;/li&gt;
&lt;li&gt;Como isso muda se a cobrança virar um evento assíncrono, consumido de uma fila, em vez de uma chamada síncrona?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;fontes&quot;&gt;Fontes&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#fontes&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;IETF — &lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc9110.html#section-9.2.2&quot;&gt;RFC 9110: HTTP Semantics, seção 9.2.2 (métodos idempotentes)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;IETF — &lt;a href=&quot;https://datatracker.ietf.org/doc/draft-ietf-httpapi-idempotency-key-header/&quot;&gt;The Idempotency-Key HTTP Header Field (Internet-Draft)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Stripe — &lt;a href=&quot;https://docs.stripe.com/api/idempotent_requests&quot;&gt;Idempotent requests&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;PostgreSQL 17 — &lt;a href=&quot;https://www.postgresql.org/docs/17/index-unique-checks.html&quot;&gt;Index Uniqueness Checks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;PostgreSQL 17 — &lt;a href=&quot;https://www.postgresql.org/docs/17/sql-insert.html&quot;&gt;INSERT (ON CONFLICT e RETURNING)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;PostgreSQL 17 — &lt;a href=&quot;https://www.postgresql.org/docs/17/ddl-constraints.html&quot;&gt;Constraints (Unique Constraints)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;MITRE — &lt;a href=&quot;https://cwe.mitre.org/data/definitions/367.html&quot;&gt;CWE-367: Time-of-check Time-of-use (TOCTOU) Race Condition&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Apache Kafka — &lt;a href=&quot;https://kafka.apache.org/42/design/design/&quot;&gt;Design: Message Delivery Semantics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS — &lt;a href=&quot;https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/standard-queues-at-least-once-delivery.html&quot;&gt;Amazon SQS at-least-once delivery&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS — &lt;a href=&quot;https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/FIFO-queues-exactly-once-processing.html&quot;&gt;Exactly-once processing in Amazon SQS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;RabbitMQ — &lt;a href=&quot;https://www.rabbitmq.com/docs/reliability&quot;&gt;Reliability Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;ByteByteGo — &lt;a href=&quot;https://bytebytego.com/guides/how-to-avoid-double-payment/&quot;&gt;How to Avoid Double Payment&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>Arquitetura</category><category>Pagamentos</category><category>Idempotência</category><category>Banco de Dados</category></item><item><title>Arquitetura de ledger — partidas dobradas, saldos e conciliação</title><link>https://cesarschutz.com.br/posts/arquitetura-de-ledger/</link><guid isPermaLink="true">https://cesarschutz.com.br/posts/arquitetura-de-ledger/</guid><description>O que 12 artigos ensinam sobre ledgers de grau financeiro: registro append-only, double-entry garantido pelo banco, saldos materializados, idempotência e conciliação como entregável de engenharia — com exemplos em Java.</description><pubDate>Thu, 28 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Todo sistema que movimenta valor — dinheiro, créditos, pontos — esbarra nos mesmos problemas: como garantir que nada seja criado nem destruído por acidente, como responder “qual era o saldo naquela data” e como perceber quando o número exibido divergiu da verdade. Os artigos resumidos aqui chegam à mesma resposta: &lt;strong&gt;ledger append-only + saldo materializado + conciliação&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Este post resume 12 artigos sobre o assunto — as séries &lt;em&gt;How to Scale a Ledger&lt;/em&gt; e &lt;em&gt;Accounting for Developers&lt;/em&gt;, da Modern Treasury, e mais três textos independentes —, com os exemplos de código convertidos para Java. Cada seção traz a ideia central do artigo, os pontos importantes e o link para o original. Se contabilidade é novidade para você, vale ler antes as seções 8 a 10 (os fundamentos) e depois voltar ao começo.&lt;/p&gt;
&lt;p&gt;O modelo que todos compartilham tem três peças: a &lt;strong&gt;account&lt;/strong&gt; (conta), a &lt;strong&gt;transaction&lt;/strong&gt; (o movimento completo) e as &lt;strong&gt;entries&lt;/strong&gt; (os lançamentos de débito e crédito que compõem a transaction):&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cesarschutz.com.br/posts/arquitetura-de-ledger/modelo-account-transaction-entry.svg&quot; alt=&quot;O modelo central do ledger: Transaction agrupa entries imutáveis que debitam e creditam accounts&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;vocabulário-mínimo&quot;&gt;Vocabulário mínimo&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#vocabulário-mínimo&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Os termos abaixo aparecem o tempo todo no post:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Ledger (livro-razão):&lt;/strong&gt; o registro de todos os movimentos de valor de um sistema.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Double-entry (partidas dobradas):&lt;/strong&gt; todo movimento tem pelo menos um débito e um crédito, e a soma dos débitos é igual à soma dos créditos. Dinheiro sempre sai de algum lugar e entra em outro.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Débito e crédito:&lt;/strong&gt; não significam “tira” e “põe”. O efeito de cada um depende do tipo da conta (a &lt;em&gt;normalidade&lt;/em&gt;, explicada nas seções 3 e 8).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Append-only:&lt;/strong&gt; só se acrescentam registros; nada é alterado nem apagado. Um erro se corrige com um novo lançamento, que compensa o anterior.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Saldo materializado:&lt;/strong&gt; saldo pré-calculado e guardado para leitura rápida, mas sempre derivado dos lançamentos.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Drift:&lt;/strong&gt; divergência entre o saldo guardado e a soma dos lançamentos.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Conciliação:&lt;/strong&gt; comparar dois registros que deveriam bater (saldo guardado × lançamentos, ou ledger × extrato do banco) e tratar as diferenças.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Idempotência:&lt;/strong&gt; repetir a mesma requisição não repete o efeito. O tema tem post próprio: &lt;a href=&quot;https://cesarschutz.com.br/posts/cobranca-duplicada-no-retry/&quot;&gt;Cobrança duplicada no retry&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Liquidação (settlement):&lt;/strong&gt; o momento em que o dinheiro efetivamente muda de mãos, em geral depois da autorização.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;1-ledger-confiável-em-sistema-event-driven-sem-transações-gigantes&quot;&gt;1. Ledger confiável em sistema event-driven, sem transações gigantes&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#1-ledger-confiável-em-sistema-event-driven-sem-transações-gigantes&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Visão geral:&lt;/strong&gt; como construir um ledger de grau financeiro num sistema distribuído e orientado a eventos &lt;strong&gt;sem&lt;/strong&gt; envolver cada operação numa transação de banco gigante. A consistência vem de concorrência otimista, particionamento e restrições de unicidade — não de locks globais.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pontos importantes:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Event sourcing:&lt;/strong&gt; cada mudança vira um evento imutável (depósito, saque, bloqueio de valor). Em vez de guardar só o saldo final, você guarda todos os eventos, e o saldo pode ser reconstruído a partir deles. Isso dá trilha de auditoria completa e permite reprocessar tudo (&lt;em&gt;replay&lt;/em&gt;) se a lógica mudar.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CQRS (separação entre comando e consulta):&lt;/strong&gt; o lado de comando recebe “Sacar $30” e, se o comando for válido, emite o evento &lt;code&gt;FundsWithdrawn&lt;/code&gt;. O lado de consulta assina os eventos e atualiza um &lt;em&gt;read model&lt;/em&gt; (uma tabela otimizada para leitura, como &lt;code&gt;account_balances&lt;/code&gt;). A consulta de saldo lê essa tabela em vez de reprocessar todos os eventos.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;O problema de concorrência:&lt;/strong&gt; dois eventos quase simultâneos na mesma conta (depósito de $50 e saque de $30) podem ler dados desatualizados e perder ou contar dinheiro em dobro se não houver controle.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Três técnicas para resolver sem transação gigante:&lt;/strong&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Controle de concorrência otimista (OCC):&lt;/strong&gt; cada conta — o &lt;em&gt;aggregate&lt;/em&gt;, no vocabulário de DDD — tem uma &lt;code&gt;version&lt;/code&gt; inteira. Ao gravar um evento, você informa a versão que leu; se ela mudou porque outro evento entrou antes, a gravação falha e você recarrega o estado e tenta de novo (&lt;em&gt;compare-and-swap&lt;/em&gt;). O assunto é aprofundado em &lt;a href=&quot;https://cesarschutz.com.br/posts/bloqueio-otimista-e-pessimista/&quot;&gt;Bloqueio otimista e pessimista&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Particionamento por conta:&lt;/strong&gt; sistemas como o Kafka particionam as mensagens por uma chave, aqui o &lt;code&gt;account_id&lt;/code&gt;. Cada partição é consumida em sequência por uma única thread, o que garante ordem serial dentro da mesma conta e paralelismo entre contas diferentes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Restrição de unicidade&lt;/strong&gt; em &lt;code&gt;(aggregate_id, version)&lt;/code&gt;: o próprio banco rejeita a segunda inserção com a mesma versão. É a salvaguarda do &lt;em&gt;compare-and-swap&lt;/em&gt; no nível do banco.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Idempotência no replay:&lt;/strong&gt; ao reprocessar eventos, guarde o &lt;code&gt;aggregate_id&lt;/code&gt; e a versão já aplicados; se o evento já foi aplicado, pule. Assim nada é contado duas vezes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Saldo bloqueado × disponível:&lt;/strong&gt; ledgers reais precisam de estados como valores reservados (por exemplo, a autorização de um cartão, que bloqueia o valor antes de liquidar). Modele eventos &lt;code&gt;FundsHeld&lt;/code&gt;, &lt;code&gt;FundsReleased&lt;/code&gt; e &lt;code&gt;FundsSettled&lt;/code&gt; e mantenha uma projeção com &lt;code&gt;held_balance&lt;/code&gt; e &lt;code&gt;available_balance&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;O event store se resume a uma tabela &lt;code&gt;events&lt;/code&gt; (o artigo usa MySQL; aqui, a versão em PostgreSQL):&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://cesarschutz.com.br/_astro/ec.bzl1c.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://cesarschutz.com.br/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;events.sql&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;TABLE&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;events&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;id           &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;BIGSERIAL&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;PRIMARY KEY&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;aggregate_id &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;VARCHAR&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;50&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;)  &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;NOT NULL&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;version&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;INT&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;NOT NULL&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;event_type   &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;VARCHAR&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;255&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;NOT NULL&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;payload      JSONB        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;NOT NULL&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;created_at   &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;TIMESTAMPTZ&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;NOT NULL&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;UNIQUE&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (aggregate_id, &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;version&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;O &lt;code&gt;append&lt;/code&gt; confere a versão esperada e grava os eventos numa transação curta, que envolve só os eventos daquela conta. A conferência sozinha não basta: dois escritores podem ler a mesma versão ao mesmo tempo. Quem fecha essa brecha é a restrição de unicidade — o segundo &lt;code&gt;INSERT&lt;/code&gt; falha com o código &lt;code&gt;23505&lt;/code&gt; (&lt;code&gt;unique_violation&lt;/code&gt;) e vira um conflito de versão:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;EventStore.java&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// Event store com checagem de versão esperada (compare-and-swap)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;EventStore&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;final&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; String UNIQUE_VIOLATION &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;23505&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// SQLSTATE do PostgreSQL&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;final&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; DataSource dataSource;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;EventStore&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(DataSource &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;dataSource&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;.dataSource &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; dataSource;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// Versão atual (maior version) de uma conta&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;getCurrentVersion&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(Connection &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;conn&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, String &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;accountId&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;throws&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; SQLException {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;String sql &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;SELECT COALESCE(MAX(version), 0) FROM events WHERE aggregate_id = ?&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;try&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (PreparedStatement stmt &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; conn.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;prepareStatement&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(sql)) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;stmt.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;setString&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, accountId);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;try&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (ResultSet rs &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; stmt.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;executeQuery&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;()) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; rs.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;next&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; rs.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;getInt&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// Append com verificação de versão esperada&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;append&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(String &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;accountId&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;expectedVersion&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, List&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;DomainEvent&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;events&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;throws&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; SQLException {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;try&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (Connection conn &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; dataSource.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;getConnection&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;()) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;conn.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;setAutoCommit&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;); &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// transação curta: só os eventos desta conta&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;try&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// 1) Checa a versão mais recente e compara com a esperada&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; currentVersion &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;getCurrentVersion&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(conn, accountId);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (currentVersion &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;!=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; expectedVersion) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;throw&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;VersionConflictException&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                        &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;Version conflict! Expected &quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; expectedVersion &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;, got &quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; currentVersion);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// 2) Insere cada evento com a versão seguinte&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;String insert &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;INSERT INTO events &quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;+&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                    &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;(aggregate_id, version, event_type, payload, created_at) &quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;+&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                    &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;VALUES (?, ?, ?, CAST(? AS JSONB), NOW())&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;try&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (PreparedStatement stmt &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; conn.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;prepareStatement&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(insert)) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (DomainEvent event &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; events) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;                        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;stmt.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;setString&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, accountId);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;                        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;stmt.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;setInt&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;currentVersion);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;                        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;stmt.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;setString&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, event.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;getClass&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;getName&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;());&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;                        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;stmt.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;setString&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, event.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;toPayloadJson&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;());&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;                        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;stmt.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;executeUpdate&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;                    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;conn.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;commit&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;catch&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (SQLException | RuntimeException &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;ex&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;conn.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;rollback&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// 3) Outro escritor gravou a mesma (aggregate_id, version) entre a leitura e o insert&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (ex &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;instanceof&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; SQLException sqlEx &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; UNIQUE_VIOLATION.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;equals&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(sqlEx.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;getSQLState&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;())) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;throw&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;VersionConflictException&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;Version conflict on insert&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, sqlEx);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;throw&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; ex;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Quem chama trata o conflito recarregando o estado e revalidando o comando — o saldo pode não ser mais suficiente depois do evento que entrou antes:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;WithdrawHandler.java&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// Retry em caso de conflito de versão&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;handleWithdrawCommand&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(String accountId, BigDecimal withdrawAmount)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;throws SQLException {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; attempt &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;; ; attempt&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// Reconstrói o estado da conta a partir dos eventos&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;List&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;DomainEvent&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&gt; events &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; eventStore.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;loadEvents&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(accountId);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;AccountAggregate aggregate &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;AccountAggregate&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(accountId, events);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; expectedVersion &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; aggregate.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;getVersion&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(); &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// ex.: 5&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// Regra de negócio: recusa o saque se o saldo não for suficiente&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;List&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;DomainEvent&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&gt; newEvents &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; aggregate.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;withdraw&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(withdrawAmount);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;try&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;eventStore.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;append&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(accountId, expectedVersion, newEvents);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;catch&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (VersionConflictException &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;ex&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// Outro evento entrou antes: recarrega e revalida na próxima volta&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (attempt &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; MAX_ATTEMPTS) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;throw&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; ex;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Fonte:&lt;/strong&gt; &lt;a href=&quot;https://new2026.medium.com/building-a-reliable-ledger-in-an-event-sourced-system-without-big-db-transactions-879061a7ff87&quot;&gt;Building a Reliable Ledger in an Event-Sourced System Without Big DB Transactions&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;2-how-to-scale-a-ledger-part-i--por-que-usar-um-banco-de-ledger&quot;&gt;2. How to Scale a Ledger, Part I — por que usar um banco de ledger&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#2-how-to-scale-a-ledger-part-i--por-que-usar-um-banco-de-ledger&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Visão geral:&lt;/strong&gt; toda empresa que move dinheiro em escala precisa de um ledger — um banco de dados double-entry — como fonte única da verdade, em vez de espalhar a lógica financeira pelos modelos de domínio (o objeto “pedido”, “corrida”, “reserva”).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pontos importantes:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Por que os modelos tradicionais falham em escala:&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;as exigências de relatório e auditoria crescem (é preciso saber origem e destino de cada centavo);&lt;/li&gt;
&lt;li&gt;os dados ficam fragmentados entre vários serviços e produtos SaaS que não se integram;&lt;/li&gt;
&lt;li&gt;a performance degrada (jobs de repasse perdem o prazo, a checagem de autorização de cartão atrasa);&lt;/li&gt;
&lt;li&gt;cenários de falha (cobrança a mais, saldo insuficiente, fraude) ficam mais frequentes e difíceis de reverter.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Modelo de dados central:&lt;/strong&gt; &lt;strong&gt;accounts&lt;/strong&gt; (porções separadas de valor), &lt;strong&gt;transactions&lt;/strong&gt; (eventos monetários atômicos) e &lt;strong&gt;entries&lt;/strong&gt; (os débitos e créditos individuais que compõem a transaction).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;As quatro garantias de um ledger escalável:&lt;/strong&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Imutabilidade&lt;/strong&gt; — estados passados sempre podem ser recuperados; as mudanças são permanentes e consultáveis.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Double-entry obrigatório&lt;/strong&gt; — não dá para mover dinheiro sem informar a origem e o destino.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Controle de concorrência&lt;/strong&gt; — o mesmo dinheiro não pode ser gasto duas vezes, mesmo com escritas paralelas ou fora de ordem.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Agregações eficientes&lt;/strong&gt; — somar eventos financeiros de um período é rápido.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;O problema da “tradução”:&lt;/strong&gt; engenheiros de produto falam a língua do domínio (pedidos, corridas, reservas), mas precisam traduzi-la para a língua de finanças (débitos, créditos, ativos, passivos) — com eventos que chegam fragmentados, de APIs diferentes e de registros que mudam.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Consequência real de erros:&lt;/strong&gt; um líder de produto de uma grande empresa de pagamentos contou que, todo mês, o time financeiro notava “alguns milhões de dólares” sumidos do ledger. O dinheiro continuava no banco; o que se perdia era a &lt;strong&gt;atribuição&lt;/strong&gt; (o registro de a quem ele pertence).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Por que não construir do zero:&lt;/strong&gt; um ledger double-entry performático e confiável leva anos de esforço e dezenas de engenheiros sênior; hoje há bancos de dados de ledger prontos.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Fonte:&lt;/strong&gt; &lt;a href=&quot;https://www.moderntreasury.com/journal/how-to-scale-a-ledger-part-i&quot;&gt;How to Scale a Ledger, Part I&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;3-part-ii--mapeando-eventos-financeiros&quot;&gt;3. Part II — mapeando eventos financeiros&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#3-part-ii--mapeando-eventos-financeiros&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Visão geral:&lt;/strong&gt; detalha os três objetos centrais (account, entry, transaction), como mapear eventos financeiros reais neles e como calcular os diferentes tipos de saldo.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pontos importantes:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Dois princípios básicos:&lt;/strong&gt; todo evento monetário é registrado num modelo double-entry consistente, e &lt;strong&gt;todos os saldos&lt;/strong&gt; mostrados a usuários e sistemas são &lt;strong&gt;lidos desse modelo&lt;/strong&gt; (nunca de um campo mutável solto).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Account = porção separada de valor&lt;/strong&gt;, numa moeda. Ela deve informar três saldos:
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Posted (lançado):&lt;/strong&gt; apenas o que já liquidou.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pending (pendente):&lt;/strong&gt; o que já liquidou mais o que deve liquidar.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Available (disponível):&lt;/strong&gt; o que pode sair agora — desconta as saídas previstas e não conta as entradas ainda não liquidadas.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;O ciclo de vida de um cartão de crédito&lt;/strong&gt; ilustra como cada ação afeta esses saldos: compra de passagem (pendente), liquidação, pagamento da fatura, pré-autorização de hotel e sua liberação.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Entry = registro imutável de movimento.&lt;/strong&gt; Saldos nunca são alterados diretamente; toda mudança entra como uma entry. Os campos centrais (&lt;code&gt;amount&lt;/code&gt;, &lt;code&gt;direction&lt;/code&gt;) são imutáveis; o único campo mutável é &lt;code&gt;discarded_at&lt;/code&gt;, usado só para substituir entries pendentes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Descartar × reverter:&lt;/strong&gt; só entries &lt;code&gt;pending&lt;/code&gt; podem ser substituídas; entries &lt;code&gt;posted&lt;/code&gt; e &lt;code&gt;archived&lt;/code&gt; são permanentes. Descartar a pendente, em vez de criar uma entry de reversão, mantém o histórico limpo — os débitos reais do cliente não se misturam com débitos criados só para reverter.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Normalidade da conta (ponto-chave):&lt;/strong&gt; cada conta é &lt;strong&gt;debit normal&lt;/strong&gt; (usos de recursos: ativos e despesas — aumentam com débito) ou &lt;strong&gt;credit normal&lt;/strong&gt; (fontes de recursos: passivos, patrimônio líquido e receita — aumentam com crédito). Com números positivos e negativos, um depósito não conseguiria aumentar as duas contas envolvidas ao mesmo tempo, porque uma delas teria de ficar negativa para a soma fechar.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cinco campos para calcular qualquer saldo:&lt;/strong&gt; &lt;code&gt;posted_debits&lt;/code&gt;, &lt;code&gt;posted_credits&lt;/code&gt;, &lt;code&gt;pending_debits&lt;/code&gt;, &lt;code&gt;pending_credits&lt;/code&gt; e &lt;code&gt;normal_balance&lt;/code&gt;. O ledger deve buscar esses cinco campos rapidamente e só calcular os saldos quando alguém pedir.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As fórmulas do artigo, em Java (lembrando que, no modelo da Modern Treasury, os totais &lt;code&gt;pending_*&lt;/code&gt; já incluem o que está &lt;code&gt;posted&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;BalanceCalculator.java&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;enum&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;NormalBalance&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;CREDIT&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;DEBIT&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;BalanceCalculator&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// Posted balance&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; BigDecimal &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;postedBalance&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(NormalBalance &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;normal&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;                                    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;BigDecimal &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;postedCredits&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;                                    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;BigDecimal &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;postedDebits&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;switch&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (normal) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;case&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; CREDIT &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; postedCredits.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;subtract&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(postedDebits);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;case&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; DEBIT  &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; postedDebits.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;subtract&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(postedCredits);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// Pending balance&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; BigDecimal &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;pendingBalance&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(NormalBalance &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;normal&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;                                     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;BigDecimal &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;pendingCredits&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;                                     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;BigDecimal &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;pendingDebits&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;switch&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (normal) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;case&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; CREDIT &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; pendingCredits.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;subtract&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(pendingDebits);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;case&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; DEBIT  &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; pendingDebits.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;subtract&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(pendingCredits);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// Available balance&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; BigDecimal &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;availableBalance&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(NormalBalance &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;normal&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;                                       &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;BigDecimal &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;postedCredits&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;                                       &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;BigDecimal &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;postedDebits&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;                                       &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;BigDecimal &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;pendingCredits&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;                                       &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;BigDecimal &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;pendingDebits&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;switch&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (normal) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;case&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; CREDIT &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; postedCredits.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;subtract&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(pendingDebits);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;case&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; DEBIT  &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; postedDebits.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;subtract&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(pendingCredits);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Fonte:&lt;/strong&gt; &lt;a href=&quot;https://www.moderntreasury.com/journal/how-to-scale-a-ledger-part-ii&quot;&gt;How to Scale a Ledger, Part II&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;4-part-iii--o-modelo-de-transaction&quot;&gt;4. Part III — o modelo de transaction&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#4-part-iii--o-modelo-de-transaction&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Visão geral:&lt;/strong&gt; a &lt;strong&gt;transaction&lt;/strong&gt;, que agrupa as entries, é o que garante movimento de dinheiro atômico e obriga o double-entry. Sem ela, dá para deixar o ledger inconsistente registrando só parte de um movimento.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pontos importantes:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Uma transaction garante:&lt;/strong&gt; &lt;strong&gt;atomicidade&lt;/strong&gt; (todas as entries têm sucesso ou falham juntas), &lt;strong&gt;consistência&lt;/strong&gt; (nada de mudanças parciais) e &lt;strong&gt;double-entry&lt;/strong&gt; (entries sempre balanceadas).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;O risco sem transaction:&lt;/strong&gt; se a entry de débito grava, mas a de crédito falha (por exemplo, por um problema de rede), um lado foi debitado e o outro não recebeu nada — o dinheiro se perdeu.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A API só deve permitir criar transactions, nunca entries avulsas.&lt;/strong&gt; Assim o cliente não consegue deixar um movimento pela metade; as entries são gerenciadas internamente.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Três estados da transaction:&lt;/strong&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Pending&lt;/strong&gt; (estado inicial): grava débito e crédito como &lt;code&gt;pending&lt;/code&gt;, ainda não finalizados.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Posted&lt;/strong&gt; (finalizado): como entries são imutáveis, as pendentes são descartadas e novas entries &lt;code&gt;posted&lt;/code&gt; são criadas.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Archived&lt;/strong&gt; (cancelado antes de ser lançado): só transactions pendentes podem ser arquivadas; as entries pendentes são descartadas e novas entries &lt;code&gt;archived&lt;/code&gt; são criadas, preservando o histórico do cancelamento.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tudo ou nada:&lt;/strong&gt; todas as entries não descartadas de uma transaction têm o mesmo status que ela, e por isso mudam de status juntas.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Fonte:&lt;/strong&gt; &lt;a href=&quot;https://www.moderntreasury.com/journal/how-to-scale-a-ledger-part-iii&quot;&gt;How to Scale a Ledger, Part III&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;5-part-iv--registrar--autorizar&quot;&gt;5. Part IV — registrar × autorizar&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#5-part-iv--registrar--autorizar&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Visão geral:&lt;/strong&gt; um ledger opera em dois modos. No &lt;strong&gt;recording&lt;/strong&gt; (registro), ele só anota o que já aconteceu em outros sistemas; no &lt;strong&gt;authorizing&lt;/strong&gt; (autorização), aprova ou nega transactions ativamente. A maioria das implementações só escala bem em um dos dois; o ideal é escolher o modo no nível da entry.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pontos importantes:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Recording:&lt;/strong&gt; alto volume de escrita (milhares por segundo ou mais), processamento assíncrono (as leituras podem ficar alguns segundos defasadas, com consistência eventual) e suporte a consultas complexas. Aqui o ledger &lt;strong&gt;não é&lt;/strong&gt; a fonte da verdade — ele reflete o que já aconteceu em outro lugar (banco, processadora de cartão).
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;effective_at&lt;/code&gt;:&lt;/strong&gt; data e hora informadas pelo cliente para retroagir a transaction ao momento em que o dinheiro realmente se moveu. Todas as entries herdam o &lt;code&gt;effective_at&lt;/code&gt; da transaction.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Versões do saldo da conta:&lt;/strong&gt; como saldos passados podem mudar, cada conta tem uma &lt;code&gt;version&lt;/code&gt; incrementada sempre que uma entry é criada ou modificada. Cada entry guarda o &lt;code&gt;account_version&lt;/code&gt; correspondente, o que permite saber exatamente quais entries compõem um saldo.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Casos de uso:&lt;/strong&gt; exibir detalhes da conta, repasses (payouts), gestão de empréstimos, cripto.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Authorizing:&lt;/strong&gt; consistência &lt;em&gt;read-after-write&lt;/em&gt; (a leitura logo após a escrita já enxerga o novo saldo), volume menor (a performance degrada perto de 100 entries por segundo numa mesma conta), verificações de saldo e controle de concorrência. É o modo para mover dinheiro em tempo real, validando se há saldo — carteiras digitais e autorização de cartão.
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Version locking:&lt;/strong&gt; o cliente envia a versão da conta junto com o pedido, e o ledger rejeita se a versão no banco for outra (bloqueio otimista). O algoritmo: inicia a transação de banco → grava a entry → atualiza a versão da conta com condição na versão atual → faz commit se a atualização aconteceu, senão rollback.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Balance locking:&lt;/strong&gt; o version locking sofre com &lt;em&gt;hot accounts&lt;/em&gt; — contas com tanta escrita que a versão muda antes de o cliente conseguir usá-la. A alternativa é condicionar a escrita ao &lt;strong&gt;saldo&lt;/strong&gt; (por exemplo, &lt;code&gt;gte: 0&lt;/code&gt;: só grava se o saldo não ficar negativo). No exemplo do artigo, o mesmo resultado sai em 2 chamadas em vez de 6, e a API expressa melhor a intenção.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Modo misto (o ideal):&lt;/strong&gt; decidir entre recording e authorizing &lt;strong&gt;por entry&lt;/strong&gt;, não por conta. Numa autorização de cartão, a entry da conta do cliente precisa de balance lock e consistência forte, enquanto a entry da conta da processadora (liquidada uma vez por dia) pode ter consistência eventual e alto volume. As duas continuam atômicas na mesma transaction.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Fonte:&lt;/strong&gt; &lt;a href=&quot;https://www.moderntreasury.com/journal/how-to-scale-a-ledger-part-iv&quot;&gt;How to Scale a Ledger, Part IV&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;6-part-v--imutabilidade-e-double-entry-a-fundo&quot;&gt;6. Part V — imutabilidade e double-entry a fundo&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#6-part-v--imutabilidade-e-double-entry-a-fundo&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Visão geral:&lt;/strong&gt; aprofunda duas das quatro garantias: imutabilidade (qualquer estado passado do ledger pode ser reconstruído) e double-entry (dinheiro não pode ser criado nem destruído).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pontos importantes:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Imutabilidade apesar de campos mutáveis:&lt;/strong&gt; o saldo das accounts muda, transactions passam de pending para posted ou archived, entries podem ser descartadas — mas tudo é construído sobre um &lt;strong&gt;log append-only imutável&lt;/strong&gt;. Nada é apagado de fato.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Como consultar estados passados:&lt;/strong&gt; as entries de uma conta num dado instante são as que têm &lt;code&gt;effective_at&lt;/code&gt; menor ou igual a esse instante e não tinham sido descartadas até lá (consulta abaixo).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Versões para precisão:&lt;/strong&gt; só a data e hora não bastam, porque várias entries podem ter o mesmo &lt;code&gt;effective_at&lt;/code&gt; ou &lt;code&gt;discarded_at&lt;/code&gt;. As versões da conta gravadas nas entries dizem exatamente quais entries formam um saldo, e as versões passadas da transaction permitem reconstruir estados anteriores.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Log de auditoria:&lt;/strong&gt; além do estado, registre &lt;strong&gt;o que&lt;/strong&gt; mudou, &lt;strong&gt;quem&lt;/strong&gt; mudou e &lt;strong&gt;quando&lt;/strong&gt; (várias chaves de API, usuários internos pelo painel administrativo). O artigo recomenda um log de auditoria ao lado do ledger.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Validação do double-entry:&lt;/strong&gt; toda transaction precisa de pelo menos uma entry de débito e uma de crédito, e &lt;strong&gt;débitos = créditos em cada moeda&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Por que balancear por moeda:&lt;/strong&gt; numa compra de 1 ETH com dólares, validar só o total quebra — dá para creditar ETH criado do nada e debitar dólares que simplesmente somem. O certo é &lt;strong&gt;agrupar as entries por moeda&lt;/strong&gt; e validar cada grupo. Uma conversão de moeda sempre envolve pelo menos 4 contas (a plataforma precisa de uma conta em ETH de onde sai a cripto e de uma em dólar onde entra o dinheiro do cliente); modelar com só 2 contas e uma taxa de câmbio não funciona, porque a taxa varia no tempo e não existe uma taxa única aceita por todos.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;EntryRepository.java&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// Busca as entries presentes numa conta num determinado effective time&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; List&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;Entry&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;findEntriesAt&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(String accountId, Instant timestamp) throws SQLException {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;String sql &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;SELECT * FROM entries &quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;+&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;WHERE account_id = ? &quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;+&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;  AND effective_at &amp;#x3C;= ? &quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;+&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;  AND (discarded_at IS NULL OR discarded_at &gt;= ?)&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;try&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (Connection conn &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; dataSource.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;getConnection&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;         &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;PreparedStatement stmt &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; conn.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;prepareStatement&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(sql)) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;stmt.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;setString&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, accountId);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;stmt.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;setTimestamp&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, Timestamp.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(timestamp));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;stmt.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;setTimestamp&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, Timestamp.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(timestamp));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;try&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (ResultSet rs &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; stmt.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;executeQuery&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;()) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;List&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;Entry&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&gt; entries &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; ArrayList&amp;#x3C;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;while&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (rs.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;next&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;()) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;entries.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(Entry.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;fromResultSet&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(rs));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; entries;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Fonte:&lt;/strong&gt; &lt;a href=&quot;https://www.moderntreasury.com/journal/how-to-scale-a-ledger-part-v&quot;&gt;How to Scale a Ledger, Part V&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;7-part-vi--concorrência-performance-e-o-job-de-conciliação&quot;&gt;7. Part VI — concorrência, performance e o job de conciliação&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#7-part-vi--concorrência-performance-e-o-job-de-conciliação&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Visão geral:&lt;/strong&gt; as duas últimas garantias — controle de concorrência (evitar gastar o mesmo dinheiro duas vezes) e performance (leitura rápida de saldo) — e o &lt;strong&gt;job que detecta drift no cache de saldo&lt;/strong&gt;, que fecha o padrão “registro + saldo + conciliação”. É o artigo que melhor mostra a conciliação interna na prática.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pontos importantes:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Chaves de idempotência:&lt;/strong&gt; o cenário clássico — o cliente envia o pedido, o ledger demora, o cliente estoura o timeout e tenta de novo; o pedido original termina e o ledger cria a transaction duas vezes. A solução é deduplicar com uma chave de idempotência: uma string enviada pelo cliente e &lt;strong&gt;gerada fora do loop de retry&lt;/strong&gt;, para que todas as tentativas usem a mesma. Se o ledger recebe uma chave que já conhece, devolve a resposta da primeira requisição. As chaves ficam guardadas por 24 horas.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Performance — cache de saldo:&lt;/strong&gt; calcular o saldo somando as entries é O(n) e fica lento com dezenas ou centenas de milhares de entries. A solução é &lt;strong&gt;cachear&lt;/strong&gt; &lt;code&gt;pending_debits&lt;/code&gt;, &lt;code&gt;pending_credits&lt;/code&gt;, &lt;code&gt;posted_debits&lt;/code&gt; e &lt;code&gt;posted_credits&lt;/code&gt; numa linha da conta.
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Cache do saldo atual:&lt;/strong&gt; reflete todas as entries e é atualizado &lt;strong&gt;de forma síncrona&lt;/strong&gt; quando entries de autorização são gravadas, porque é ele que sustenta o balance locking. Quem faz a conta de forma atômica é o banco.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cache de saldo por data efetiva:&lt;/strong&gt; mais complexo, com duas abordagens — &lt;em&gt;anchoring&lt;/em&gt; (guarda o saldo do fim de cada dia e aplica as entries do dia por cima) e &lt;em&gt;resulting balances&lt;/em&gt; (guarda o saldo resultante após cada entry, útil para contas com muitas entries no mesmo dia). No anchoring, a atualização é assíncrona: as entries entram numa fila e o cache é atualizado em lotes.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Monitorando o drift do cache (o job de conciliação):&lt;/strong&gt; ler o saldo do cache melhora a performance, mas o cache pode divergir das entries, que são a fonte da verdade. O tratamento tem três passos:
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Verificar regularmente&lt;/strong&gt; se o saldo em cache de cada conta bate com a &lt;strong&gt;soma das entries&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Desligar automaticamente&lt;/strong&gt; a leitura do cache nas contas com drift.&lt;/li&gt;
&lt;li&gt;Oferecer &lt;strong&gt;ferramentas de backfill&lt;/strong&gt; (recalcular o cache a partir das entries) e um runbook para o plantão investigar e corrigir o drift.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://cesarschutz.com.br/posts/arquitetura-de-ledger/job-de-conciliacao.svg&quot; alt=&quot;O job de conciliação compara a soma das entries com o saldo em cache e, se houver drift, desliga a leitura do cache e aciona backfill e runbook&quot;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Tópicos avançados de escala:&lt;/strong&gt; &lt;em&gt;account categories&lt;/em&gt; (um modelo em grafo para agregar grupos de contas em relatórios); busca de transactions com paginação por cursor, não por offset; &lt;strong&gt;filas de escrita assíncronas&lt;/strong&gt; que absorvem picos de carga — as fintechs líderes passam facilmente de 5.000 QPS (requisições por segundo); e sharding de contas entre bancos, seja manual, seja com bancos distribuídos como Spanner ou CockroachDB — com o desafio de manter a atomicidade do double-entry entre shards.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;RetryComIdempotencia.java&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// Idempotency key gerada FORA do loop de retry (mesma string em todas as tentativas)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;String idempotencyKey &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; UUID.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;randomUUID&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;toString&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;TransactionResponse response &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; attempt &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;; attempt &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;&amp;#x3C;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; MAX_ATTEMPTS; attempt&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;response &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;createTransaction&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(idempotencyKey);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (response.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;isSuccessful&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;()) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;break&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;ReconciliationJob.java&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// Conceito do job de conciliação: comparar saldo em cache com a soma das entries&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;reconcileAccount&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(String accountId) throws SQLException {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;BigDecimal cachedBalance &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; balanceCache.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;getBalance&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(accountId);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;BigDecimal computedBalance &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;sumAllEntries&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(accountId); &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// SUM() sobre as entries&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (cachedBalance.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;compareTo&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(computedBalance) &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;!=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// Drift detectado: desliga a leitura do cache e alerta o plantão (backfill + runbook)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;balanceCache.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;disableReads&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(accountId);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;alerting.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;raiseDrift&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(accountId, cachedBalance, computedBalance);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Fonte:&lt;/strong&gt; &lt;a href=&quot;https://www.moderntreasury.com/journal/how-to-scale-a-ledger-part-vi&quot;&gt;How to Scale a Ledger, Part VI&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;8-accounting-for-developers-part-i--os-fundamentos&quot;&gt;8. Accounting for Developers, Part I — os fundamentos&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#8-accounting-for-developers-part-i--os-fundamentos&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Visão geral:&lt;/strong&gt; introdução à contabilidade para desenvolvedores: os conceitos de double-entry traduzidos para termos técnicos, para quem constrói sistemas que movem dinheiro.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pontos importantes:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Princípio central:&lt;/strong&gt; toda transaction registra &lt;strong&gt;de onde o dinheiro veio&lt;/strong&gt; e &lt;strong&gt;em que foi usado&lt;/strong&gt;. Com isso você reconstrói saldos em qualquer data, rastreia o movimento com auditabilidade total e alinha a lógica do sistema com as finanças reais.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Falha mais comum:&lt;/strong&gt; o software criar ou destruir registros de dinheiro por acidente. Os sintomas: registros internos diferentes do extrato do banco, ferramentas de conciliação apontando divergências, saldos que não fazem sentido diante das transactions. Uber, Square e Airbnb são citadas como empresas que adotaram double-entry.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Conceitos:&lt;/strong&gt; &lt;strong&gt;account&lt;/strong&gt; (porção separada de valor), &lt;strong&gt;transaction&lt;/strong&gt; (evento atômico que afeta saldos; tem pelo menos duas entries, afeta duas ou mais contas e mantém o ledger balanceado) e &lt;strong&gt;ledger&lt;/strong&gt; (log de eventos com impacto monetário).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Não altere saldos diretamente:&lt;/strong&gt; guarde transactions imutáveis e &lt;strong&gt;sempre calcule o saldo a partir delas&lt;/strong&gt;. Alterar o saldo direto parece mais simples e eficiente, mas gera um sistema propenso a erros difíceis de detectar e de conciliar.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Debit normal × credit normal:&lt;/strong&gt; contas debit normal representam o que você tem ou os usos do dinheiro (ativos, despesas) e aumentam com débito; contas credit normal representam o que você deve ou as fontes do dinheiro (passivos, patrimônio líquido, receita) e aumentam com crédito.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;table-wrap&quot;&gt;


































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Tipo de conta&lt;/th&gt;&lt;th&gt;Débito&lt;/th&gt;&lt;th&gt;Crédito&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Ativo (asset)&lt;/td&gt;&lt;td&gt;+&lt;/td&gt;&lt;td&gt;−&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Passivo (liability)&lt;/td&gt;&lt;td&gt;−&lt;/td&gt;&lt;td&gt;+&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Patrimônio líquido (equity)&lt;/td&gt;&lt;td&gt;−&lt;/td&gt;&lt;td&gt;+&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Receita (revenue)&lt;/td&gt;&lt;td&gt;−&lt;/td&gt;&lt;td&gt;+&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Despesa (expense)&lt;/td&gt;&lt;td&gt;+&lt;/td&gt;&lt;td&gt;−&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Ledger balanceado:&lt;/strong&gt; a soma dos saldos das contas credit normal é igual à soma dos saldos das contas debit normal. Se não bate, o sistema criou ou perdeu dinheiro do nada.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Detalhe contraintuitivo:&lt;/strong&gt; duas contas podem aumentar &lt;strong&gt;ao mesmo tempo&lt;/strong&gt;. No exemplo do artigo, a Modern Bagelry, uma loja on-line de bagels, recebe um aporte de $1 milhão: o caixa (ativo, debit normal) sobe com um débito e o patrimônio líquido (credit normal) sobe com um crédito.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Fonte:&lt;/strong&gt; &lt;a href=&quot;https://www.moderntreasury.com/journal/accounting-for-developers-part-i&quot;&gt;Accounting for Developers, Part I&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;9-part-ii--o-ledger-de-uma-carteira-digital&quot;&gt;9. Part II — o ledger de uma carteira digital&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#9-part-ii--o-ledger-de-uma-carteira-digital&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Visão geral:&lt;/strong&gt; aplica os fundamentos construindo, passo a passo, o ledger de uma carteira digital no estilo do Venmo: requisitos → plano de contas → modelagem das transactions → modelagem do banco.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pontos importantes:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Plano de contas (chart of accounts) do app:&lt;/strong&gt; &lt;strong&gt;Cash&lt;/strong&gt; (o dinheiro real no banco) → ativo, debit normal; &lt;strong&gt;saldo da carteira de cada usuário&lt;/strong&gt; (uma conta por usuário) → passivo, credit normal (a empresa “deve” esse dinheiro ao usuário); &lt;strong&gt;taxas de processamento de cartão&lt;/strong&gt; → despesa, debit normal; &lt;strong&gt;receita&lt;/strong&gt; com tarifas → credit normal.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Três transactions modeladas:&lt;/strong&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Transferência ($100 de A para B):&lt;/strong&gt; debita a carteira de quem envia e credita a de quem recebe.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Depósito com cartão:&lt;/strong&gt; crédito de $300 na carteira, contrabalançado por dois débitos — taxa de cartão ($6, ou 2%) e caixa ($294). Um único evento com várias entries.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Saque:&lt;/strong&gt; saque de $500 com tarifa de 0,5% ($2,50) → debita $502,50 da carteira, credita $497,50 no caixa e $2,50 na receita.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Modelagem do banco:&lt;/strong&gt; &lt;code&gt;accounts&lt;/code&gt; (&lt;code&gt;id&lt;/code&gt;, &lt;code&gt;user_id&lt;/code&gt;, &lt;code&gt;account_type&lt;/code&gt;, &lt;code&gt;normality&lt;/code&gt;), &lt;code&gt;transactions&lt;/code&gt; (&lt;code&gt;id&lt;/code&gt;, &lt;code&gt;timestamp&lt;/code&gt;, &lt;code&gt;description&lt;/code&gt;) e &lt;code&gt;entries&lt;/code&gt; (&lt;code&gt;id&lt;/code&gt;, &lt;code&gt;transaction_id&lt;/code&gt;, &lt;code&gt;account_id&lt;/code&gt;, &lt;code&gt;amount&lt;/code&gt;, &lt;code&gt;direction&lt;/code&gt;). &lt;strong&gt;Invariante a garantir:&lt;/strong&gt; soma dos débitos = soma dos créditos &lt;strong&gt;em cada transaction&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;ModeloLedger.java&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;enum&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;Normality&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;DEBIT&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;CREDIT&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;enum&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;Direction&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;DEBIT&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;CREDIT&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// userId é nulo nas contas internas; accountType: &quot;USER_WALLET&quot;, &quot;CASH&quot;, &quot;REVENUE&quot;, &quot;CARD_FEES&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;Account&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;long&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; id, Long userId, String accountType, Normality normality) {}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;Entry&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;long&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; id, &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;long&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; transactionId, &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;long&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; accountId, BigDecimal amount, Direction direction) {}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;LedgerTransaction&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;long&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; id, Instant timestamp, String description, List&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;Entry&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; entries) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// Invariante: soma dos débitos == soma dos créditos&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;boolean&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;isBalanced&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;total&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(Direction.DEBIT).&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;compareTo&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;total&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(Direction.CREDIT)) &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; BigDecimal &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;total&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(Direction &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;direction&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; entries.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;stream&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;filter&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(e &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; e.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;direction&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; direction)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;map&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(Entry&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;amount)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;reduce&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(BigDecimal.ZERO, BigDecimal&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;add);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;O depósito do artigo, montado com esse modelo:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;Deposito.java&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// Contas: 1 = carteira do Art, 2 = taxas de cartão, 3 = caixa&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; deposito &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;LedgerTransaction&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, Instant.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;now&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(), &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;Depósito com cartão&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, List.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;Entry&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;100&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;BigDecimal&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;300.00&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;), Direction.CREDIT),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;Entry&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;101&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;BigDecimal&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;6.00&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;), Direction.DEBIT),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;Entry&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;102&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;BigDecimal&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;294.00&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;), Direction.DEBIT)));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;System.out.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(deposito.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;isBalanced&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;()); &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// true&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Com várias moedas, a mesma checagem deve ser feita em cada moeda, como mostra a Part V.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fonte:&lt;/strong&gt; &lt;a href=&quot;https://www.moderntreasury.com/journal/accounting-for-developers-part-ii&quot;&gt;Accounting for Developers, Part II&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;10-part-iii--um-marketplace-de-empréstimos&quot;&gt;10. Part III — um marketplace de empréstimos&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#10-part-iii--um-marketplace-de-empréstimos&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Visão geral:&lt;/strong&gt; aplica os princípios num marketplace de empréstimos entre pessoas (P2P), com juros, amortização, investidores e tomadores.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pontos importantes:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Dois tipos de dado:&lt;/strong&gt; o &lt;strong&gt;histórico&lt;/strong&gt; (o que já aconteceu, baseado em transactions lançadas) fica no ledger; o &lt;strong&gt;prospectivo&lt;/strong&gt; (taxas de juros, prazos, divisão de cada parcela entre juros e principal) fica &lt;strong&gt;fora&lt;/strong&gt; dele, numa &lt;strong&gt;tabela de amortização&lt;/strong&gt;. Separar os dois mantém o ledger limpo.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Plano de contas:&lt;/strong&gt; caixa (debit normal), receita de juros (credit normal) e &lt;strong&gt;duas contas por usuário&lt;/strong&gt; (principal e juros). As contas do investidor são credit normal (a plataforma deve a ele); as do tomador são debit normal (ele deve à plataforma).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cinco transactions modeladas:&lt;/strong&gt; depósito do investidor; desembolso ao tomador; &lt;strong&gt;apropriação mensal de juros&lt;/strong&gt;; pagamento mensal do tomador; pagamento ao investidor no vencimento. Na apropriação de juros, o investidor recebe 4,8% ao ano e o tomador paga 12%: credita $40 por mês nos juros do investidor, debita $50 nos juros do tomador, e a diferença de $10 vai para a &lt;strong&gt;receita&lt;/strong&gt; — o spread da plataforma.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Arquitetura final:&lt;/strong&gt; um &lt;strong&gt;ledger central&lt;/strong&gt; com as restrições de double-entry, um &lt;strong&gt;Transaction Logic Service&lt;/strong&gt; (converte eventos e webhooks em entries válidas), uma &lt;strong&gt;tabela de amortização&lt;/strong&gt; (calcula as parcelas) e um &lt;strong&gt;plano de contas&lt;/strong&gt; com pelo menos 6 tipos de conta.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Fonte:&lt;/strong&gt; &lt;a href=&quot;https://www.moderntreasury.com/journal/accounting-for-developers-part-iii&quot;&gt;Accounting for Developers, Part III&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;11-arquitetura-de-plataformas-de-fidelidade-open-loyalty&quot;&gt;11. Arquitetura de plataformas de fidelidade (Open Loyalty)&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#11-arquitetura-de-plataformas-de-fidelidade-open-loyalty&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Visão geral:&lt;/strong&gt; a arquitetura de plataformas de pontos e fidelidade — um domínio onde o mesmo padrão de ledger aparece fora do dinheiro. O artigo defende plataformas modulares e API-first, com o &lt;strong&gt;ledger de pontos&lt;/strong&gt; como um dos componentes centrais.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pontos importantes:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Componentes centrais:&lt;/strong&gt; motor de regras (avalia as ações do cliente e decide o que disparar), &lt;strong&gt;ledger de pontos&lt;/strong&gt; (cada ponto ganho, resgatado, transferido ou expirado, com trilha de auditoria completa), serviço de entrega das recompensas (&lt;em&gt;fulfillment&lt;/em&gt;), camada de API, camada de eventos e mensageria e camada de dados do cliente.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;O ledger de pontos é um dos componentes mais exigentes:&lt;/strong&gt; quando o cliente conclui uma compra, &lt;strong&gt;os pontos devem ser creditados exatamente uma vez&lt;/strong&gt;, mesmo que a requisição seja repetida ou processada duas vezes. Um ledger que erra isso produz erros de saldo difíceis de detectar e caros de corrigir. Plataformas modernas o tratam como &lt;strong&gt;serviço independente&lt;/strong&gt;, e não como um campo no cadastro do cliente.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Idempotência na API é essencial&lt;/strong&gt; — concessão ou resgate duplicado de pontos é um risco operacional real.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fluxo ponta a ponta:&lt;/strong&gt; compra → chamada de API → a camada de eventos roteia para o motor de regras → o motor avalia campanhas e categoria do cliente → o fulfillment gera a recompensa → &lt;strong&gt;o ledger é atualizado com registro de auditoria&lt;/strong&gt; → o evento “recompensa emitida” segue para os outros sistemas. As falhas ficam contidas: se o fulfillment atrasa, a atualização do ledger ainda termina.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Quando essa complexidade não é necessária:&lt;/strong&gt; num programa simples, no início ou em um único canal, uma plataforma tudo-em-um é mais pragmática. A arquitetura deve seguir as necessidades reais do programa.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Fonte:&lt;/strong&gt; &lt;a href=&quot;https://www.openloyalty.io/insider/loyalty-system-architecture-how-modern-platforms-are-built&quot;&gt;Loyalty System Architecture&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;12-payment-ledger-architecture-trio--os-6-fatores&quot;&gt;12. Payment Ledger Architecture (Trio) — os 6 fatores&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#12-payment-ledger-architecture-trio--os-6-fatores&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Visão geral:&lt;/strong&gt; define um ledger de pagamentos por seis fatores e apresenta a stack em que a maioria dos sistemas em produção converge. É o resumo mais direto e prático do conjunto.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Os 6 fatores:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Double-entry como invariante do banco, não da aplicação:&lt;/strong&gt; débito, crédito e metadados da mesma entry são gravados numa &lt;strong&gt;única transação atômica de banco&lt;/strong&gt;. Uma CHECK constraint ou uma validação antes do commit confirma que a entry soma zero. Errar isso gera drift de saldo silencioso.
Um cuidado prático: no PostgreSQL, uma CHECK constraint só enxerga a linha que está sendo gravada. Se débito e crédito ficam em linhas separadas, a soma precisa ser validada por um &lt;em&gt;constraint trigger&lt;/em&gt; adiado para o fim da transação (&lt;code&gt;DEFERRABLE INITIALLY DEFERRED&lt;/code&gt;) ou pela aplicação antes do commit.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Derivar saldos das entries, nunca guardar um saldo corrente:&lt;/strong&gt; uma coluna &lt;code&gt;balance&lt;/code&gt; mutável &lt;strong&gt;sofre drift&lt;/strong&gt; com escrita concorrente, falha parcial, correção manual ou migração. Em escala, fazer &lt;code&gt;SUM()&lt;/code&gt; a cada leitura fica caro, então crie um &lt;strong&gt;saldo materializado&lt;/strong&gt;: uma visão em cache, otimizada para leitura, recalculada quando novas entries são lançadas — e &lt;strong&gt;sempre conferida contra as entries na conciliação&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Journals imutáveis com reversões explícitas (sem UPDATE nem DELETE):&lt;/strong&gt; o &lt;em&gt;journal&lt;/em&gt; é a tabela de lançamentos, e ela precisa ser inalterável para valer em auditorias (SOC 2, PCI DSS, exames de AML/KYC). Reverter = lançar uma &lt;strong&gt;nova&lt;/strong&gt; entry compensatória. O usuário de banco usado pelo posting engine (o serviço que grava os lançamentos) &lt;strong&gt;não deve ter permissão&lt;/strong&gt; de UPDATE ou DELETE nas tabelas de journal.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Modelo de três saldos:&lt;/strong&gt; &lt;strong&gt;ledger balance&lt;/strong&gt; (liquidado), &lt;strong&gt;pending&lt;/strong&gt; (em trânsito) e &lt;strong&gt;available&lt;/strong&gt; (o que pode ser gasto agora). Juntar os três num só aumenta o risco de o cliente gastar mais do que tem, inclusive valores bloqueados ou ainda em trânsito.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CQRS — separar escrita e leitura:&lt;/strong&gt; a escrita é fortemente consistente, atômica e durável; a leitura é rápida, via saldo materializado. Quando o saldo alimenta uma &lt;strong&gt;decisão financeira&lt;/strong&gt;, o posting engine valida contra o journal, não contra a visão materializada, que pode estar defasada.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Conciliação como entregável de engenharia, não planilha do financeiro:&lt;/strong&gt; há a correção &lt;strong&gt;interna&lt;/strong&gt; (entries balanceadas, saldos derivados batendo com o journal) e a &lt;strong&gt;externa&lt;/strong&gt; (o ledger batendo com processadora, bandeira, banco parceiro e câmara de compensação). O caminho é um &lt;strong&gt;pipeline automatizado&lt;/strong&gt; que roda todo dia ou após cada janela de liquidação, compara linha a linha e expõe as divergências com classificação de severidade (diferença de prazo × divergência real), alertas e acompanhamento das exceções. Segundo o artigo, o colapso da Synapse em 2024 foi em grande parte uma falha de conciliação do ledger.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;A stack de referência:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cesarschutz.com.br/posts/arquitetura-de-ledger/stack-de-referencia.svg&quot; alt=&quot;Stack de referência: posting engine grava no journal do PostgreSQL e publica no Kafka; o balance materializer mantém os saldos, com Redis para contas quentes; o pipeline de conciliação compara arquivos externos com o journal e registra exceções&quot;&gt;&lt;/p&gt;
&lt;p&gt;No diagrama, o &lt;strong&gt;posting engine&lt;/strong&gt; valida o double-entry, grava as entries atomicamente no &lt;strong&gt;journal&lt;/strong&gt; (PostgreSQL, append-only) e publica o evento &lt;code&gt;JournalEntryPosted&lt;/code&gt; no &lt;strong&gt;Kafka&lt;/strong&gt;. O &lt;strong&gt;balance materializer&lt;/strong&gt; consome esses eventos e mantém os três saldos, usando &lt;strong&gt;Redis&lt;/strong&gt; para contas muito movimentadas. O &lt;strong&gt;pipeline de conciliação&lt;/strong&gt; roda em jobs agendados (Airflow, Dagster ou Prefect): lê os arquivos externos — relatórios da processadora, extratos bancários, arquivos da bandeira —, compara cada linha com o journal e grava as divergências numa tabela de exceções, com alertas. Para volumes muito altos, o artigo cita bancos SQL distribuídos como CockroachDB e Google Spanner.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Construir ou comprar:&lt;/strong&gt; construa se o ledger é diferencial competitivo, se o time já construiu ledgers em produção ou se os requisitos vão além do que um Ledger-as-a-Service (LaaS, ledger oferecido como serviço) suporta. Use LaaS ou open-source (Formance Ledger, Blnk) se o ledger é infraestrutura e o tempo até o mercado importa mais. A maioria começa melhor com LaaS ou open-source e migra para uma solução própria quando a plataforma deixa de atender algum requisito.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fonte:&lt;/strong&gt; &lt;a href=&quot;https://trio.dev/payment-ledger-architecture-fintech/&quot;&gt;Payment Ledger Architecture: How Modern Fintechs Design Ledgers&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;síntese--o-padrão-em-que-os-12-artigos-convergem&quot;&gt;Síntese — o padrão em que os 12 artigos convergem&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#síntese--o-padrão-em-que-os-12-artigos-convergem&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Independentemente do domínio — banco digital, carteira, marketplace, programa de pontos —, o desenho final é o mesmo:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Cada movimento&lt;/strong&gt; é uma entry imutável num ledger append-only, protegida por &lt;strong&gt;chave de idempotência&lt;/strong&gt; para nunca ser lançada duas vezes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;O saldo&lt;/strong&gt; é um &lt;strong&gt;saldo materializado&lt;/strong&gt;: um cache de leitura rápida, atualizado de forma síncrona quando sustenta autorizações (seção 7) ou de forma assíncrona a partir dos eventos (seção 12) — mas sempre &lt;strong&gt;derivado e reconstruível&lt;/strong&gt; a partir das entries, nunca a fonte da verdade.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A conciliação&lt;/strong&gt; é um job ou pipeline que soma as entries de cada conta, compara com o saldo materializado, detecta drift, desliga a leitura do cache da conta afetada e alerta — e, havendo sistema externo, confere o ledger também contra ele.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Double-entry vale além do dinheiro.&lt;/strong&gt; Levando o raciocínio dos artigos para um programa de pontos: ao conceder pontos, credita-se a conta do cliente e debita-se uma conta interna de pontos emitidos. Assim a soma sempre fecha e qualquer drift fica detectável.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Quando um efeito externo (a captura no parceiro, por exemplo) pode dar certo sem que o registro local seja gravado, a conciliação externa ganha um aliado: gravar a intenção antes de agir, tema de &lt;a href=&quot;https://cesarschutz.com.br/posts/efeito-externo-sem-registro-local/&quot;&gt;Efeito externo sem registro local&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;fontes&quot;&gt;Fontes&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#fontes&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Os 12 artigos resumidos:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://new2026.medium.com/building-a-reliable-ledger-in-an-event-sourced-system-without-big-db-transactions-879061a7ff87&quot;&gt;Building a Reliable Ledger in an Event-Sourced System Without Big DB Transactions&lt;/a&gt; — Medium&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.moderntreasury.com/journal/how-to-scale-a-ledger-part-i&quot;&gt;How to Scale a Ledger, Part I&lt;/a&gt; — Modern Treasury&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.moderntreasury.com/journal/how-to-scale-a-ledger-part-ii&quot;&gt;How to Scale a Ledger, Part II&lt;/a&gt; — Modern Treasury&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.moderntreasury.com/journal/how-to-scale-a-ledger-part-iii&quot;&gt;How to Scale a Ledger, Part III&lt;/a&gt; — Modern Treasury&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.moderntreasury.com/journal/how-to-scale-a-ledger-part-iv&quot;&gt;How to Scale a Ledger, Part IV&lt;/a&gt; — Modern Treasury&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.moderntreasury.com/journal/how-to-scale-a-ledger-part-v&quot;&gt;How to Scale a Ledger, Part V&lt;/a&gt; — Modern Treasury&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.moderntreasury.com/journal/how-to-scale-a-ledger-part-vi&quot;&gt;How to Scale a Ledger, Part VI&lt;/a&gt; — Modern Treasury&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.moderntreasury.com/journal/accounting-for-developers-part-i&quot;&gt;Accounting for Developers, Part I&lt;/a&gt; — Modern Treasury&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.moderntreasury.com/journal/accounting-for-developers-part-ii&quot;&gt;Accounting for Developers, Part II&lt;/a&gt; — Modern Treasury&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.moderntreasury.com/journal/accounting-for-developers-part-iii&quot;&gt;Accounting for Developers, Part III&lt;/a&gt; — Modern Treasury&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.openloyalty.io/insider/loyalty-system-architecture-how-modern-platforms-are-built&quot;&gt;Loyalty system architecture: How modern platforms are built&lt;/a&gt; — Open Loyalty&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://trio.dev/payment-ledger-architecture-fintech/&quot;&gt;Payment Ledger Architecture: How Modern Fintechs Design Ledgers&lt;/a&gt; — Trio&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Documentação usada nos exemplos e observações técnicas:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.postgresql.org/docs/current/ddl-constraints.html&quot;&gt;PostgreSQL — Constraints&lt;/a&gt; (CHECK constraint só valida a linha gravada)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.postgresql.org/docs/current/sql-createtrigger.html&quot;&gt;PostgreSQL — CREATE TRIGGER&lt;/a&gt; (constraint triggers adiados)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.postgresql.org/docs/current/errcodes-appendix.html&quot;&gt;PostgreSQL — Error Codes&lt;/a&gt; (&lt;code&gt;23505 unique_violation&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>Arquitetura</category><category>Pagamentos</category><category>Banco de Dados</category><category>Idempotência</category></item><item><title>SNS MessageAttributes e Filter Policy — filtrando mensagens antes do SQS</title><link>https://cesarschutz.com.br/posts/sns-filter-policy/</link><guid isPermaLink="true">https://cesarschutz.com.br/posts/sns-filter-policy/</guid><description>Como fazer o SNS entregar a cada fila SQS só as mensagens que interessam: atributos de mensagem, filter policy na assinatura, filtro por atributo ou pelo corpo, operadores, limites e cuidados.</description><pubDate>Wed, 20 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Quando um tópico SNS tem várias filas SQS assinando (o chamado &lt;em&gt;fan-out&lt;/em&gt;), &lt;strong&gt;cada fila recebe, por padrão, todas as mensagens publicadas no tópico&lt;/strong&gt;. Se o consumidor só se interessa por um tipo de evento, ele precisa receber, ler e descartar o resto, pagando por isso. A &lt;strong&gt;filter policy&lt;/strong&gt; resolve esse problema: é uma regra em JSON configurada na &lt;strong&gt;assinatura&lt;/strong&gt; que faz o próprio SNS decidir quais mensagens entrega àquela fila. O que não passa no filtro não é enviado à fila.&lt;/p&gt;
&lt;p&gt;Neste post: como marcar a mensagem com &lt;strong&gt;MessageAttributes&lt;/strong&gt; no produtor, como escrever e aplicar a filter policy, como o SNS avalia a regra, a diferença entre filtrar por atributo e pelo corpo da mensagem, e os limites e cuidados.&lt;/p&gt;
&lt;h2 id=&quot;os-termos-em-uma-frase&quot;&gt;Os termos em uma frase&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#os-termos-em-uma-frase&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Tópico&lt;/strong&gt;: o canal onde o produtor publica. &lt;strong&gt;Assinatura&lt;/strong&gt; (&lt;em&gt;subscription&lt;/em&gt;): o vínculo entre o tópico e um destino, como uma fila SQS.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MessageAttributes&lt;/strong&gt;: metadados opcionais enviados &lt;strong&gt;junto com a mensagem, mas fora do corpo&lt;/strong&gt;. Cada atributo tem nome, tipo (&lt;code&gt;String&lt;/code&gt;, &lt;code&gt;String.Array&lt;/code&gt;, &lt;code&gt;Number&lt;/code&gt; ou &lt;code&gt;Binary&lt;/code&gt;) e valor.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Filter policy&lt;/strong&gt;: JSON guardado na assinatura que diz quais mensagens ela aceita. Assinatura sem filter policy recebe tudo.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;como-funciona-na-prática&quot;&gt;Como funciona na prática&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#como-funciona-na-prática&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Ao publicar, o produtor adiciona um atributo que identifica o tipo de evento. Com Spring Cloud AWS, os headers da mensagem viram MessageAttributes do SNS (um header &lt;code&gt;String&lt;/code&gt; vira atributo do tipo &lt;code&gt;String&lt;/code&gt;), e o &lt;code&gt;convertAndSend&lt;/code&gt; do &lt;code&gt;SnsTemplate&lt;/code&gt; criado pela autoconfiguração serializa o evento em JSON no corpo:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://cesarschutz.com.br/_astro/ec.bzl1c.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://cesarschutz.com.br/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;Produtor (Spring Cloud AWS)&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;snsTemplate.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;convertAndSend&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;topicArn,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;event,                                    &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// corpo: o evento serializado em JSON&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;Map.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;eventType&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;OrderCreatedEvent&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;)  &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// header que vira MessageAttribute no SNS&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Cuidado com a variante &lt;code&gt;send(topicArn, message)&lt;/code&gt;: ela não converte o payload e publica o &lt;code&gt;toString()&lt;/code&gt; do objeto, então só use com payload já em &lt;code&gt;String&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Sem Spring, o equivalente é preencher &lt;code&gt;MessageAttributes&lt;/code&gt; na chamada &lt;code&gt;Publish&lt;/code&gt; da API do SNS, com &lt;code&gt;DataType&lt;/code&gt; &lt;code&gt;String&lt;/code&gt; e &lt;code&gt;StringValue&lt;/code&gt; &lt;code&gt;OrderCreatedEvent&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Na assinatura da fila, você configura a filter policy:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;Filter policy da assinatura&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;{ &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;&quot;eventType&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;: [&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;OrderCreatedEvent&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;] }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Ela é gravada no atributo &lt;code&gt;FilterPolicy&lt;/code&gt; da assinatura, pelo console, pela CLI, pelos SDKs ou por CloudFormation:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;Aplicando pela AWS CLI&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;aws&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;sns&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;set-subscription-attributes&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;--subscription-arn&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;arn:aws:sns:...&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;--attribute-name&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;FilterPolicy&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;--attribute-value&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&apos;{&quot;eventType&quot;: [&quot;OrderCreatedEvent&quot;]}&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Resultado: essa fila só recebe mensagens com &lt;code&gt;eventType = OrderCreatedEvent&lt;/code&gt;. Os outros tipos publicados no mesmo tópico não são entregues a ela. O filtro vale &lt;strong&gt;por assinatura&lt;/strong&gt;: no diagrama abaixo, cada fila tem o seu, e uma mensagem que não casa com nenhum deles não chega a fila nenhuma.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cesarschutz.com.br/posts/sns-filter-policy/filter-policy-fanout.svg&quot; alt=&quot;Produtor publica três tipos de evento; o SNS entrega OrderCreatedEvent só à fila A, OrderCancelledEvent só à fila B, e OrderShippedEvent a nenhuma&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;como-o-sns-avalia-a-regra&quot;&gt;Como o SNS avalia a regra&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#como-o-sns-avalia-a-regra&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Chaves diferentes = E (AND)&lt;/strong&gt;: a mensagem precisa satisfazer todas as chaves da policy.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Valores no mesmo array = OU (OR)&lt;/strong&gt;: basta casar com um deles.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Atributo ausente reprova&lt;/strong&gt;: se a policy exige &lt;code&gt;eventType&lt;/code&gt; e a mensagem não tem esse atributo, ela não é entregue (a exceção é &lt;code&gt;&quot;exists&quot;: false&lt;/code&gt;, que casa justamente com a ausência). Atributos da mensagem que a policy não cita são ignorados.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Comparação de strings diferencia maiúsculas de minúsculas&lt;/strong&gt;, a menos que você use &lt;code&gt;equals-ignore-case&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Além da igualdade exata, a policy aceita operadores. Os mais úteis:&lt;/p&gt;
&lt;div class=&quot;table-wrap&quot;&gt;












































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Operador&lt;/th&gt;&lt;th&gt;Exemplo&lt;/th&gt;&lt;th&gt;Casa quando&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;anything-but&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;[{&quot;anything-but&quot;: [&quot;OrderShippedEvent&quot;]}]&lt;/code&gt;&lt;/td&gt;&lt;td&gt;o valor &lt;strong&gt;não&lt;/strong&gt; é nenhum dos listados&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;prefix&lt;/code&gt; / &lt;code&gt;suffix&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;[{&quot;prefix&quot;: &quot;Order&quot;}]&lt;/code&gt;&lt;/td&gt;&lt;td&gt;o valor começa (ou termina) com o texto&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;equals-ignore-case&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;[{&quot;equals-ignore-case&quot;: &quot;ordercreatedevent&quot;}]&lt;/code&gt;&lt;/td&gt;&lt;td&gt;igualdade sem diferenciar maiúsculas de minúsculas&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;numeric&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;[{&quot;numeric&quot;: [&quot;&gt;=&quot;, 100, &quot;&amp;#x3C;&quot;, 500]}]&lt;/code&gt;&lt;/td&gt;&lt;td&gt;o número está na faixa&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;exists&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;[{&quot;exists&quot;: true}]&lt;/code&gt;&lt;/td&gt;&lt;td&gt;o atributo está presente (ou ausente, com &lt;code&gt;false&lt;/code&gt;)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;cidr&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;[{&quot;cidr&quot;: &quot;10.0.0.0/24&quot;}]&lt;/code&gt;&lt;/td&gt;&lt;td&gt;o IP pertence à sub-rede&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;$or&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;{&quot;$or&quot;: [{...}, {...}]}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;uma das condições (entre chaves diferentes) é verdadeira&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Um exemplo combinando AND, OR e operadores: aceita pedidos criados &lt;strong&gt;ou&lt;/strong&gt; cancelados, de lojas cujo código começa com &lt;code&gt;loja-&lt;/code&gt;, com valor a partir de 100 (publique &lt;code&gt;total&lt;/code&gt; como atributo do tipo &lt;code&gt;Number&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;Filter policy com operadores&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;&quot;eventType&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;: [&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;OrderCreatedEvent&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;OrderCancelledEvent&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;],&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;&quot;store&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;: [{ &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;&quot;prefix&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;loja-&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; }],&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;&quot;total&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;: [{ &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;&quot;numeric&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;: [&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;&gt;=&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;100&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;] }]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h2 id=&quot;filtrar-por-atributo-ou-pelo-corpo&quot;&gt;Filtrar por atributo ou pelo corpo&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#filtrar-por-atributo-ou-pelo-corpo&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;O atributo &lt;code&gt;FilterPolicyScope&lt;/code&gt; da assinatura define onde o SNS procura os campos:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;MessageAttributes&lt;/code&gt;&lt;/strong&gt; (padrão): a policy é comparada com os atributos da mensagem. Não aceita policy aninhada, compara só atributos &lt;code&gt;String&lt;/code&gt;, &lt;code&gt;String.Array&lt;/code&gt; e &lt;code&gt;Number&lt;/code&gt;, e &lt;strong&gt;ignora atributos &lt;code&gt;Binary&lt;/code&gt;&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;MessageBody&lt;/code&gt;&lt;/strong&gt;: a policy é comparada com os campos do corpo, que precisa ser um objeto JSON válido. Aceita policy aninhada, espelhando a estrutura do JSON.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Por exemplo, para um corpo &lt;code&gt;{&quot;order&quot;: {&quot;status&quot;: &quot;CREATED&quot;, &quot;total&quot;: 250}}&lt;/code&gt;, esta policy aninhada aceita a mensagem:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;Filter policy com escopo MessageBody&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;&quot;order&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;&quot;status&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;: [&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;CREATED&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;],&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;&quot;total&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;: [{ &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;&quot;numeric&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;: [&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;&gt;=&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;100&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;] }]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Filtrar pelo corpo é útil quando você não controla o produtor e ele não publica atributos. Mesmo assim, o filtro por atributo continua sendo o caminho padrão por dois motivos: &lt;strong&gt;é gratuito&lt;/strong&gt;, enquanto o filtro pelo corpo é cobrado por GB de payload analisado (contando tanto as mensagens entregues quanto as filtradas), e não acopla a regra ao formato do payload.&lt;/p&gt;
&lt;h2 id=&quot;por-que-isso-importa&quot;&gt;Por que isso importa&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#por-que-isso-importa&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Sem filter policy&lt;/strong&gt;: todas as mensagens do tópico chegam à fila, e o consumidor recebe e descarta o que não é dele.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Com filter policy&lt;/strong&gt;: só o que interessa chega. São menos requisições ao SQS (que cobra por requisição: envio, recebimento e exclusão contam), menos transferência de dados do SNS para o SQS (cobrada por volume entregue) e menos processamento desperdiçado no consumidor.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;O filtro fica na assinatura, não no produtor&lt;/strong&gt;: o produtor não precisa saber quem consome. É o desacoplamento clássico do &lt;em&gt;pub/sub&lt;/em&gt; (publicação e assinatura), só que com entrega seletiva.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;MessageAttributes também servem para outras coisas além de filtro, como propagar o ID de rastreamento entre serviços; veja &lt;a href=&quot;https://cesarschutz.com.br/posts/w3c-trace-context/&quot;&gt;W3C Trace Context&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;limites-e-cuidados&quot;&gt;Limites e cuidados&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#limites-e-cuidados&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Tamanho da policy&lt;/strong&gt;: no máximo &lt;strong&gt;5 chaves&lt;/strong&gt; e &lt;strong&gt;150 combinações&lt;/strong&gt;. As combinações são o produto da quantidade de valores de cada chave: chaves com 3, 1 e 2 valores dão 3 × 1 × 2 = 6. A policy pode ter até 256 KB.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Quantidade de policies&lt;/strong&gt;: por padrão, até &lt;strong&gt;200 por tópico&lt;/strong&gt; e &lt;strong&gt;10.000 por conta&lt;/strong&gt;, ajustáveis pelo Service Quotas.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mudança não é instantânea&lt;/strong&gt;: criar ou alterar uma filter policy leva &lt;strong&gt;até 15 minutos&lt;/strong&gt; para valer por completo (consistência eventual). Não conclua que o filtro falhou logo após o deploy.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Raw message delivery&lt;/strong&gt;: com &lt;em&gt;raw message delivery&lt;/em&gt; ligado (a fila recebe a mensagem sem o envelope JSON do SNS), a assinatura SQS aceita &lt;strong&gt;no máximo 10 atributos&lt;/strong&gt;; mensagens com mais que isso são descartadas. Atenção com frameworks: o Spring Cloud AWS também envia como atributos os headers &lt;code&gt;id&lt;/code&gt; e &lt;code&gt;timestamp&lt;/code&gt; que toda &lt;code&gt;Message&lt;/code&gt; do Spring recebe automaticamente.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Um filtro errado descarta mensagens em silêncio&lt;/strong&gt;: um nome de atributo digitado errado faz a mensagem simplesmente não ser entregue. Monitore a métrica &lt;code&gt;NumberOfNotificationsFilteredOut&lt;/code&gt; do CloudWatch (e as variantes &lt;code&gt;-NoMessageAttributes&lt;/code&gt; e &lt;code&gt;-InvalidAttributes&lt;/code&gt;) para perceber quando o filtro barra mais do que deveria.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;fontes&quot;&gt;Fontes&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#fontes&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;AWS — &lt;a href=&quot;https://docs.aws.amazon.com/sns/latest/dg/sns-message-filtering.html&quot;&gt;Amazon SNS message filtering&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS — &lt;a href=&quot;https://docs.aws.amazon.com/sns/latest/dg/sns-subscription-filter-policies.html&quot;&gt;Amazon SNS subscription filter policies&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS — &lt;a href=&quot;https://docs.aws.amazon.com/sns/latest/dg/subscription-filter-policy-constraints.html&quot;&gt;Filter policy constraints in Amazon SNS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS — &lt;a href=&quot;https://docs.aws.amazon.com/sns/latest/dg/and-or-logic.html&quot;&gt;AND/OR logic&lt;/a&gt;, &lt;a href=&quot;https://docs.aws.amazon.com/sns/latest/dg/attribute-key-matching.html&quot;&gt;Key matching&lt;/a&gt;, &lt;a href=&quot;https://docs.aws.amazon.com/sns/latest/dg/string-value-matching.html&quot;&gt;String value matching&lt;/a&gt; e &lt;a href=&quot;https://docs.aws.amazon.com/sns/latest/dg/numeric-value-matching.html&quot;&gt;Numeric value matching&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS — &lt;a href=&quot;https://docs.aws.amazon.com/sns/latest/dg/example-filter-policies.html&quot;&gt;Amazon SNS example filter policies&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS — &lt;a href=&quot;https://docs.aws.amazon.com/sns/latest/dg/message-filtering-apply.html&quot;&gt;Applying a subscription filter policy in Amazon SNS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS — &lt;a href=&quot;https://docs.aws.amazon.com/sns/latest/api/API_SetSubscriptionAttributes.html&quot;&gt;SetSubscriptionAttributes (FilterPolicyScope)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS — &lt;a href=&quot;https://docs.aws.amazon.com/sns/latest/dg/sns-message-attributes.html&quot;&gt;Amazon SNS message attributes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS — &lt;a href=&quot;https://docs.aws.amazon.com/sns/latest/dg/sns-monitoring-using-cloudwatch.html&quot;&gt;Monitoring Amazon SNS topics using CloudWatch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS — &lt;a href=&quot;https://aws.amazon.com/sns/pricing/&quot;&gt;Amazon SNS pricing&lt;/a&gt; e &lt;a href=&quot;https://aws.amazon.com/sqs/pricing/&quot;&gt;Amazon SQS pricing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Spring Cloud AWS — &lt;a href=&quot;https://docs.awspring.io/spring-cloud-aws/docs/3.4.0/reference/html/index.html#sns-template&quot;&gt;Reference: SNS Template&lt;/a&gt;, código-fonte de &lt;a href=&quot;https://github.com/awspring/spring-cloud-aws/blob/main/spring-cloud-aws-sns/src/main/java/io/awspring/cloud/sns/core/SnsHeaderConverterUtil.java&quot;&gt;SnsHeaderConverterUtil&lt;/a&gt; (headers viram atributos), &lt;a href=&quot;https://github.com/awspring/spring-cloud-aws/blob/main/spring-cloud-aws-sns/src/main/java/io/awspring/cloud/sns/core/TopicMessageChannel.java&quot;&gt;TopicMessageChannel&lt;/a&gt; (publicação) e &lt;a href=&quot;https://github.com/awspring/spring-cloud-aws/blob/main/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/sns/SnsAutoConfiguration.java&quot;&gt;SnsAutoConfiguration&lt;/a&gt; (conversor JSON do &lt;code&gt;SnsTemplate&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>Arquitetura</category><category>AWS</category><category>Mensageria</category></item><item><title>W3C Trace Context — correlacionando logs entre microsserviços com o traceparent</title><link>https://cesarschutz.com.br/posts/w3c-trace-context/</link><guid isPermaLink="true">https://cesarschutz.com.br/posts/w3c-trace-context/</guid><description>O padrão W3C que leva o mesmo ID de rastreamento por todos os serviços de uma operação: o traceparent e o tracestate, valores inválidos, a granularidade certa e o ID atravessando o outbox.</description><pubDate>Wed, 20 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Quando uma operação passa por vários serviços, cada um grava seus próprios logs. Sem um identificador comum, reconstruir o que aconteceu com &lt;strong&gt;uma&lt;/strong&gt; operação vira garimpo: buscar por horário, por ID de cliente, torcer para os relógios baterem. E se cada ferramenta de tracing usa um header próprio, o ID se perde na primeira fronteira entre fornecedores.&lt;/p&gt;
&lt;p&gt;O &lt;strong&gt;W3C Trace Context&lt;/strong&gt; resolve isso. É uma recomendação do W3C que padroniza como o contexto de rastreamento (quem é a operação e de onde veio a chamada) é propagado entre serviços, de forma que qualquer ferramenta entenda. O campo central é o &lt;code&gt;traceparent&lt;/code&gt;: com o valor dele em mãos, uma única busca na ferramenta de observabilidade mostra tudo o que aconteceu com a operação, do serviço que a originou até o último consumidor.&lt;/p&gt;
&lt;p&gt;Este post mostra a anatomia do &lt;code&gt;traceparent&lt;/code&gt; e do &lt;code&gt;tracestate&lt;/code&gt;, os valores que a especificação considera inválidos, a granularidade certa para jobs em lote e como o ID atravessa um fluxo assíncrono com outbox pattern e SNS.&lt;/p&gt;
&lt;h2 id=&quot;trace-span-e-os-ids-do-traceparent&quot;&gt;Trace, span e os IDs do traceparent&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#trace-span-e-os-ids-do-traceparent&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Dois termos antes de começar:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Trace&lt;/strong&gt;: a operação inteira, com todos os passos em todos os serviços.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Span&lt;/strong&gt;: um passo dentro do trace (uma requisição recebida, uma consulta, uma publicação de mensagem). Um serviço pode gerar vários spans no mesmo trace.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;O &lt;code&gt;traceparent&lt;/code&gt; carrega dois IDs que importam para a correlação:&lt;/p&gt;
&lt;div class=&quot;table-wrap&quot;&gt;



















&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;ID&lt;/th&gt;&lt;th&gt;O que é&lt;/th&gt;&lt;th&gt;Exemplo de uso&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;trace-id&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;ID da operação inteira, o mesmo em todos os serviços&lt;/td&gt;&lt;td&gt;“me mostre tudo sobre esse lote específico”&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;parent-id&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;ID do span de quem fez a chamada (muitas ferramentas chamam de &lt;strong&gt;span-id&lt;/strong&gt;); cada passo gera o seu&lt;/td&gt;&lt;td&gt;saber de qual passo veio a chamada que gerou um log&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Além deles, o header traz a versão do formato e as flags de rastreamento.&lt;/p&gt;
&lt;h2 id=&quot;anatomia-do-traceparent&quot;&gt;Anatomia do traceparent&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#anatomia-do-traceparent&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;O valor tem quatro campos separados por hífen, sempre em hexadecimal minúsculo. Este é o exemplo da própria especificação:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://cesarschutz.com.br/_astro/ec.bzl1c.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://cesarschutz.com.br/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;traceparent&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;txt&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#e1e4e8;--1:#24292e&quot;&gt;00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div class=&quot;table-wrap&quot;&gt;


































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Campo&lt;/th&gt;&lt;th&gt;Tamanho&lt;/th&gt;&lt;th&gt;Valor no exemplo&lt;/th&gt;&lt;th&gt;O que significa&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;version&lt;/code&gt;&lt;/td&gt;&lt;td&gt;2 caracteres (1 byte)&lt;/td&gt;&lt;td&gt;&lt;code&gt;00&lt;/code&gt;&lt;/td&gt;&lt;td&gt;versão do formato; a atual é &lt;code&gt;00&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;trace-id&lt;/code&gt;&lt;/td&gt;&lt;td&gt;32 caracteres (16 bytes)&lt;/td&gt;&lt;td&gt;&lt;code&gt;4bf92f3577b34da6a3ce929d0e0e4736&lt;/code&gt;&lt;/td&gt;&lt;td&gt;ID do trace, igual em todos os serviços&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;parent-id&lt;/code&gt;&lt;/td&gt;&lt;td&gt;16 caracteres (8 bytes)&lt;/td&gt;&lt;td&gt;&lt;code&gt;00f067aa0ba902b7&lt;/code&gt;&lt;/td&gt;&lt;td&gt;ID do span de quem chamou&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;trace-flags&lt;/code&gt;&lt;/td&gt;&lt;td&gt;2 caracteres (8 bits)&lt;/td&gt;&lt;td&gt;&lt;code&gt;01&lt;/code&gt;&lt;/td&gt;&lt;td&gt;flags; hoje só o bit &lt;code&gt;sampled&lt;/code&gt; é definido&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;No total são 55 caracteres. A recomendação é enviar o nome do header em minúsculas (&lt;code&gt;traceparent&lt;/code&gt;), e quem recebe precisa aceitá-lo em qualquer caixa.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;As flags são bits, não um número.&lt;/strong&gt; O único bit definido é o menos significativo, &lt;code&gt;sampled&lt;/code&gt; (amostrado): ligado, indica que quem chamou pode ter gravado os dados do trace; desligado (&lt;code&gt;00&lt;/code&gt;), que não gravou. Como é um campo de bits, a leitura correta usa máscara (&lt;code&gt;flags &amp;#x26; 0x01&lt;/code&gt;), não comparação com &lt;code&gt;01&lt;/code&gt;. Os demais bits são reservados e devem ir zerados.&lt;/p&gt;
&lt;p&gt;A cada salto, o serviço repassa o &lt;code&gt;trace-id&lt;/code&gt; intacto e normalmente troca o &lt;code&gt;parent-id&lt;/code&gt; pelo ID do próprio span. É isso que permite montar a árvore de chamadas: o &lt;code&gt;trace-id&lt;/code&gt; agrupa, o &lt;code&gt;parent-id&lt;/code&gt; encadeia.&lt;/p&gt;
&lt;h3 id=&quot;valores-inválidos&quot;&gt;Valores inválidos&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#valores-inválidos&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A especificação define quando o &lt;code&gt;traceparent&lt;/code&gt; não vale:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Versão &lt;code&gt;ff&lt;/code&gt;&lt;/strong&gt;: proibida.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;trace-id&lt;/code&gt; só com zeros&lt;/strong&gt; (&lt;code&gt;00000000000000000000000000000000&lt;/code&gt;): inválido.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;parent-id&lt;/code&gt; só com zeros&lt;/strong&gt; (&lt;code&gt;0000000000000000&lt;/code&gt;): inválido.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Caracteres fora do hexadecimal minúsculo&lt;/strong&gt; (letras maiúsculas, por exemplo) ou tamanho errado: inválido.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Diante de um valor inválido, o serviço deve ignorar o &lt;code&gt;traceparent&lt;/code&gt; recebido: começa um trace novo e descarta o &lt;code&gt;tracestate&lt;/code&gt;. Na prática, não gere esses valores à mão. Use a biblioteca de tracing (o OpenTelemetry já usa o W3C Trace Context como propagador padrão). A especificação recomenda que o &lt;code&gt;trace-id&lt;/code&gt; seja aleatório e globalmente único, e proíbe usar dados do usuário (como o IP) como semente.&lt;/p&gt;
&lt;h2 id=&quot;o-tracestate&quot;&gt;O tracestate&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#o-tracestate&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A especificação define um segundo header, o &lt;code&gt;tracestate&lt;/code&gt;, para informações específicas de cada fornecedor de tracing. É uma lista de pares &lt;code&gt;chave=valor&lt;/code&gt; separados por vírgula, com no máximo 32 itens:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;tracestate&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;txt&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#e1e4e8;--1:#24292e&quot;&gt;rojo=00f067aa0ba902b7,congo=t61rcWkgMzE&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Ele sempre acompanha o &lt;code&gt;traceparent&lt;/code&gt;: um &lt;code&gt;tracestate&lt;/code&gt; recebido sem &lt;code&gt;traceparent&lt;/code&gt; é descartado, e se o &lt;code&gt;traceparent&lt;/code&gt; for inválido o &lt;code&gt;tracestate&lt;/code&gt; nem é lido. Para correlacionar logs, o &lt;code&gt;traceparent&lt;/code&gt; sozinho basta. O &lt;code&gt;tracestate&lt;/code&gt; só importa quando mais de uma ferramenta de tracing participa do mesmo fluxo.&lt;/p&gt;
&lt;p&gt;Os dois campos existem apenas para correlação: a especificação proíbe colocar neles dados pessoais ou sensíveis.&lt;/p&gt;
&lt;h2 id=&quot;fora-do-http-o-traceparent-em-mensagens&quot;&gt;Fora do HTTP: o traceparent em mensagens&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#fora-do-http-o-traceparent-em-mensagens&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A especificação define o formato para headers HTTP. Outros protocolos têm especificações de extensão, e em mensageria o caminho usual é levar o mesmo valor como metadado da mensagem. No SNS, isso é um &lt;strong&gt;MessageAttribute&lt;/strong&gt; (metadado enviado junto com a mensagem, fora do corpo; veja o post sobre &lt;a href=&quot;https://cesarschutz.com.br/posts/sns-filter-policy/&quot;&gt;SNS MessageAttributes e Filter Policy&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;As convenções semânticas de mensageria do OpenTelemetry chamam isso de &lt;strong&gt;contexto de criação da mensagem&lt;/strong&gt;: o produtor cria o contexto e ele deve ser propagado com a mensagem até os consumidores. Sem isso, os traces do consumidor não se ligam diretamente aos do produtor.&lt;/p&gt;
&lt;h2 id=&quot;granularidade-importa-por-lote-não-por-execução&quot;&gt;Granularidade importa: por lote, não por execução&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#granularidade-importa-por-lote-não-por-execução&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Um job que processa 50 lotes poderia usar o mesmo trace-id para todos (um trace por execução do job). Mas isso mistura os logs de todos os lotes: se o lote #47 falhar no consumidor, não dá para isolá-lo. A abordagem recomendada é gerar um &lt;strong&gt;trace-id por lote&lt;/strong&gt; (por evento de outbox). Cada evento gravado na tabela de outbox tem seu próprio &lt;code&gt;traceparent&lt;/code&gt;, que viaja com a mensagem até o consumidor.&lt;/p&gt;
&lt;p&gt;Para correlacionar todos os lotes de uma mesma execução (“quantos lotes rodaram na execução das 02h?”), use um &lt;strong&gt;job-run-id&lt;/strong&gt; separado no MDC (o contexto de log por thread do SLF4J/Logback), sem misturar com o trace-id do evento. São duas perguntas diferentes, respondidas por dois IDs diferentes. Se a ferramenta for o OpenTelemetry, dá para registrar também essa relação entre traces com &lt;strong&gt;span links&lt;/strong&gt;, que associam um span a um ou mais spans, inclusive de outros traces, indicando relação de causa.&lt;/p&gt;
&lt;h2 id=&quot;como-o-outbox-pattern-usa-na-prática&quot;&gt;Como o outbox pattern usa na prática&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#como-o-outbox-pattern-usa-na-prática&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;O &lt;strong&gt;outbox pattern&lt;/strong&gt; grava o evento numa tabela do próprio banco (a tabela outbox), na mesma transação da mudança de estado. Um processo separado, o &lt;strong&gt;relay&lt;/strong&gt;, lê essa tabela e publica os eventos no broker (detalhes no post &lt;a href=&quot;https://cesarschutz.com.br/posts/efeito-externo-sem-registro-local/&quot;&gt;Efeito externo sem registro local&lt;/a&gt;). O &lt;code&gt;traceparent&lt;/code&gt; vai junto com o evento em cada etapa:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cesarschutz.com.br/posts/w3c-trace-context/propagacao-traceparent.svg&quot; alt=&quot;O traceparent gravado no outbox viaja pelo relay e SNS até o MDC do consumidor&quot;&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;O job produtor inicia um trace novo &lt;strong&gt;por lote&lt;/strong&gt; e grava o &lt;code&gt;traceparent&lt;/code&gt; junto do evento na tabela de outbox.&lt;/li&gt;
&lt;li&gt;O relay lê o evento e o &lt;code&gt;traceparent&lt;/code&gt; da tabela.&lt;/li&gt;
&lt;li&gt;O relay publica no SNS com &lt;code&gt;PublishBatch&lt;/code&gt; (até 10 mensagens por chamada), levando o &lt;code&gt;traceparent&lt;/code&gt; como &lt;code&gt;MessageAttribute&lt;/code&gt; de cada mensagem.&lt;/li&gt;
&lt;li&gt;O SNS entrega na fila SQS. O consumidor lê o atributo, continua o mesmo trace e coloca o trace-id e o span-id no MDC. Todos os logs dele saem com esses campos.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Com isso, a ferramenta de observabilidade monta a linha do tempo produtor → mensageria → consumidor com uma busca só pelo trace-id. Para os campos do MDC aparecerem como campos pesquisáveis no log, emita logs estruturados (veja &lt;a href=&quot;https://cesarschutz.com.br/posts/logging-estruturado-spring-boot/&quot;&gt;Logging estruturado em Spring Boot&lt;/a&gt;). O mesmo &lt;code&gt;trace_id&lt;/code&gt; também pode ligar um &lt;a href=&quot;https://cesarschutz.com.br/posts/wide-events-canonical-log-lines/&quot;&gt;wide event&lt;/a&gt; ao trace distribuído.&lt;/p&gt;
&lt;p&gt;Cuidados nesse fluxo:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Raw message delivery&lt;/strong&gt;: com a entrega bruta desligada (o padrão), a mensagem chega ao SQS dentro do envelope JSON do SNS, e os atributos vêm no campo &lt;code&gt;MessageAttributes&lt;/code&gt; desse JSON. Com ela ligada, os atributos chegam como atributos da própria mensagem SQS, mas o limite é de 10: mensagens com mais atributos que isso são descartadas.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Nomes no MDC&lt;/strong&gt;: o agente Java do OpenTelemetry já injeta &lt;code&gt;trace_id&lt;/code&gt;, &lt;code&gt;span_id&lt;/code&gt; e &lt;code&gt;trace_flags&lt;/code&gt; no MDC do Logback e do Log4j. Se você preencher o MDC à mão, use os mesmos nomes em todos os serviços, ou a busca não junta os logs.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;fontes&quot;&gt;Fontes&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#fontes&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;W3C — &lt;a href=&quot;https://www.w3.org/TR/trace-context/&quot;&gt;Trace Context (W3C Recommendation, 23/11/2021)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;OpenTelemetry — &lt;a href=&quot;https://opentelemetry.io/docs/concepts/context-propagation/&quot;&gt;Context Propagation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;OpenTelemetry — &lt;a href=&quot;https://opentelemetry.io/docs/concepts/signals/traces/&quot;&gt;Traces: Span Context e Span Links&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;OpenTelemetry — &lt;a href=&quot;https://opentelemetry.io/docs/specs/semconv/messaging/messaging-spans/&quot;&gt;Semantic conventions for messaging spans&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;OpenTelemetry Java Instrumentation — &lt;a href=&quot;https://github.com/open-telemetry/opentelemetry-java-instrumentation/blob/main/docs/logger-mdc-instrumentation.md&quot;&gt;Logger MDC auto-instrumentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS — &lt;a href=&quot;https://docs.aws.amazon.com/sns/latest/dg/sns-message-attributes.html&quot;&gt;Amazon SNS message attributes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS — &lt;a href=&quot;https://docs.aws.amazon.com/sns/latest/dg/sns-large-payload-raw-message-delivery.html&quot;&gt;Amazon SNS raw message delivery&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS — &lt;a href=&quot;https://docs.aws.amazon.com/sns/latest/dg/http-notification-json.html&quot;&gt;HTTP/HTTPS notification JSON format&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS — &lt;a href=&quot;https://docs.aws.amazon.com/sns/latest/api/API_PublishBatch.html&quot;&gt;PublishBatch (Amazon SNS API Reference)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>Observabilidade</category><category>Logs</category><category>Microsserviços</category><category>Mensageria</category></item><item><title>AOP no Spring — JDK Dynamic Proxy, CGLIB e aspects customizados</title><link>https://cesarschutz.com.br/posts/aop-jdk-proxy-cglib/</link><guid isPermaLink="true">https://cesarschutz.com.br/posts/aop-jdk-proxy-cglib/</guid><description>Como o Spring aplica log, transação e métricas fora da regra de negócio: conceitos de AOP, JDK Dynamic Proxy ou CGLIB (e por que o Boot prefere CGLIB), a self-invocation e aspects próprios.</description><pubDate>Tue, 19 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Log, transação, cache, segurança e métricas aparecem em quase todo serviço, mas não fazem parte da regra de negócio de nenhum deles. &lt;strong&gt;AOP (Aspect-Oriented Programming, ou programação orientada a aspectos)&lt;/strong&gt; é o paradigma que tira esse código repetido das classes de negócio: você descreve &lt;strong&gt;onde&lt;/strong&gt; aplicar (o &lt;em&gt;pointcut&lt;/em&gt;) e &lt;strong&gt;o que&lt;/strong&gt; executar (o &lt;em&gt;advice&lt;/em&gt;) numa classe separada, chamada &lt;strong&gt;aspect&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;No Spring, é AOP que faz &lt;code&gt;@Transactional&lt;/code&gt;, &lt;code&gt;@Async&lt;/code&gt; e &lt;code&gt;@Cacheable&lt;/code&gt; funcionarem. O container troca o bean original por um &lt;strong&gt;proxy&lt;/strong&gt;, um objeto intermediário que intercepta as chamadas e roda o código extra antes e depois de delegar ao objeto real. Esse proxy é gerado de um de dois jeitos: &lt;strong&gt;JDK Dynamic Proxy&lt;/strong&gt; (implementa as interfaces do bean) ou &lt;strong&gt;CGLIB&lt;/strong&gt; (cria uma subclasse do bean).&lt;/p&gt;
&lt;p&gt;Neste post: o vocabulário básico, como cada tipo de proxy funciona e quando o Spring usa cada um, por que chamar um método da própria classe ignora o &lt;code&gt;@Transactional&lt;/code&gt; (a &lt;em&gt;self-invocation&lt;/em&gt;) e como escrever um &lt;strong&gt;aspect custom&lt;/strong&gt;, isto é, um aspect seu, para uma necessidade do seu sistema.&lt;/p&gt;
&lt;h2 id=&quot;1-o-problema-que-aop-resolve&quot;&gt;1. O problema que AOP resolve&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#1-o-problema-que-aop-resolve&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Preocupações que se repetem em muitas classes sem pertencer ao domínio delas se chamam &lt;em&gt;cross-cutting concerns&lt;/em&gt; (preocupações transversais): log, transação, cache, segurança, métricas, retry, auditoria. Sem AOP, cada método de serviço ganha seu próprio &lt;code&gt;try/finally&lt;/code&gt;, sua checagem de permissão e seu cronômetro, e a regra de negócio fica escondida no meio desse ruído.&lt;/p&gt;
&lt;p&gt;A ideia central do AOP é &lt;em&gt;modularizar&lt;/em&gt; essas preocupações em unidades separadas (os aspects) e &lt;em&gt;aplicá-las de forma declarativa&lt;/em&gt; em pontos escolhidos da execução. As classes de negócio ficam limpas, e mudar a política de log ou de métricas passa a exigir alteração em um lugar só.&lt;/p&gt;
&lt;h2 id=&quot;2-vocabulário-fundamental&quot;&gt;2. Vocabulário fundamental&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#2-vocabulário-fundamental&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Os termos não foram inventados pelo Spring: são o vocabulário geral de AOP, o mesmo usado pelo AspectJ, e o Spring os adota como são.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Aspect&lt;/strong&gt;: módulo que encapsula uma preocupação transversal. No Spring, normalmente uma classe anotada com &lt;code&gt;@Aspect&lt;/code&gt;. Ex.: &lt;code&gt;LoggingAspect&lt;/code&gt;, &lt;code&gt;MetricsAspect&lt;/code&gt;, &lt;code&gt;RetryAspect&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Join point&lt;/strong&gt;: um ponto da execução do programa onde um aspect pode atuar. &lt;strong&gt;No Spring AOP, join point é sempre a execução de um método.&lt;/strong&gt; O AspectJ vai além e cobre também acesso a campo, construção de objeto etc.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pointcut&lt;/strong&gt;: o predicado que seleciona quais join points interessam, ou seja, a expressão que diz “onde” aplicar. Ex.: &lt;code&gt;execution(* com.exemplo.servico..*(..))&lt;/code&gt; casa com todos os métodos das classes do pacote &lt;code&gt;com.exemplo.servico&lt;/code&gt; e subpacotes. O Spring usa a linguagem de pointcut do AspectJ.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Advice&lt;/strong&gt;: a ação que o aspect executa num join point, o “o que” rodar (antes, depois ou em volta do método).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Target (objeto alvo)&lt;/strong&gt;: o objeto que recebe os advices. Como o Spring AOP é baseado em proxy, esse objeto fica &lt;strong&gt;sempre atrás de um proxy&lt;/strong&gt; em tempo de execução.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AOP proxy&lt;/strong&gt;: o objeto criado pelo framework para aplicar os advices ao target. No Spring, é um JDK Dynamic Proxy ou um proxy CGLIB.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Weaving&lt;/strong&gt;: o processo de “costurar” os aspects no código da aplicação. Pode acontecer na compilação (compilador do AspectJ), no carregamento das classes (&lt;em&gt;load-time weaving&lt;/em&gt;) ou em tempo de execução, que é o caso do Spring AOP.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Introduction&lt;/strong&gt;: declarar métodos ou campos adicionais num tipo. Com ela, um bean passa a implementar uma interface nova, com a implementação fornecida pelo aspect.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;3-tipos-de-advice&quot;&gt;3. Tipos de advice&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#3-tipos-de-advice&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Cada tipo corresponde a uma anotação usada dentro de uma classe &lt;code&gt;@Aspect&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;@Before&lt;/code&gt;&lt;/strong&gt;: roda &lt;strong&gt;antes&lt;/strong&gt; do método alvo. Não consegue impedir a execução, a não ser lançando uma exceção.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;@AfterReturning&lt;/code&gt;&lt;/strong&gt;: roda &lt;strong&gt;depois&lt;/strong&gt;, se o método terminou normalmente. Tem acesso ao valor de retorno.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;@AfterThrowing&lt;/code&gt;&lt;/strong&gt;: roda quando o método lança exceção. Tem acesso à exceção.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;@After&lt;/code&gt;&lt;/strong&gt;: roda &lt;strong&gt;sempre&lt;/strong&gt; depois, com sucesso ou erro (análogo ao &lt;code&gt;finally&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;@Around&lt;/code&gt;&lt;/strong&gt;: o mais poderoso, envolve a chamada inteira. Recebe um &lt;code&gt;ProceedingJoinPoint&lt;/code&gt; e decide se chama &lt;code&gt;proceed()&lt;/code&gt;, que executa o método real. Pode trocar os argumentos, transformar o retorno ou nem chamar o método.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A documentação do Spring recomenda &lt;strong&gt;usar o tipo de advice menos poderoso que resolve o caso&lt;/strong&gt;. Se basta agir depois que o método retorna, &lt;code&gt;@AfterReturning&lt;/code&gt; é mais simples que &lt;code&gt;@Around&lt;/code&gt;, e não há &lt;code&gt;proceed()&lt;/code&gt; para esquecer de chamar (esquecer significa que o método real nunca roda).&lt;/p&gt;
&lt;h2 id=&quot;4-como-o-spring-implementa-proxy-em-tempo-de-execução&quot;&gt;4. Como o Spring implementa: proxy em tempo de execução&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#4-como-o-spring-implementa-proxy-em-tempo-de-execução&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;O AspectJ completo altera o bytecode das classes (&lt;em&gt;bytecode weaving&lt;/em&gt;). O &lt;strong&gt;Spring AOP&lt;/strong&gt;, ao contrário, &lt;strong&gt;trabalha com proxies criados em tempo de execução&lt;/strong&gt;: quando um bean tem advices aplicáveis, o container entrega um proxy no lugar da instância original. O proxy tem o mesmo tipo do bean (implementa as interfaces dele ou estende a classe), intercepta cada chamada, executa os advices e delega para o objeto real.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cesarschutz.com.br/posts/aop-jdk-proxy-cglib/proxy-e-self-invocation.svg&quot; alt=&quot;Uma chamada externa entra pelo proxy e os advices rodam; dentro do objeto real, this.metodoB() chama o método direto e o advice não roda&quot;&gt;&lt;/p&gt;
&lt;p&gt;Consequências desse modelo:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Só chamadas que passam pelo proxy são interceptadas.&lt;/strong&gt; Acesso a campo e construtor ficam de fora, e método &lt;code&gt;private&lt;/code&gt; também (não dá para interceptar o que não pode ser sobrescrito nem chamado de fora).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;O que o proxy intercepta depende do tipo dele.&lt;/strong&gt; Com JDK Dynamic Proxy, só métodos públicos declarados em interface. Com CGLIB, métodos &lt;code&gt;public&lt;/code&gt; e &lt;code&gt;protected&lt;/code&gt; (e até os de visibilidade de pacote, se necessário). A recomendação oficial, mesmo assim, é que as interações via proxy usem métodos públicos.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Self-invocation não passa pelo proxy&lt;/strong&gt; (detalhes a seguir).&lt;/li&gt;
&lt;li&gt;O Spring AOP é mais simples e mais limitado que o AspectJ completo; em troca, não exige compilador especial nem agente no carregamento das classes.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;a-pegadinha-da-self-invocation&quot;&gt;A pegadinha da self-invocation&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#a-pegadinha-da-self-invocation&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Self-invocation&lt;/em&gt; é quando um método de um bean chama outro método do &lt;strong&gt;mesmo&lt;/strong&gt; objeto. A chamada externa entrou pelo proxy e chegou ao objeto real. Dali em diante, &lt;code&gt;this&lt;/code&gt; é o objeto real, não o proxy, e qualquer chamada &lt;code&gt;this.outroMetodo()&lt;/code&gt; (ou só &lt;code&gt;outroMetodo()&lt;/code&gt;, que é a mesma coisa) vai direto, sem advice nenhum.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://cesarschutz.com.br/_astro/ec.bzl1c.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://cesarschutz.com.br/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;PedidoService.java&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;Service&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;PedidoService&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;importar&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(List&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;Pedido&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;pedidos&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (Pedido p &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; pedidos) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;salvar&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(p);   &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// o mesmo que this.salvar(p): não passa pelo proxy&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;Transactional&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;salvar&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(Pedido &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// chamado por importar(), o @Transactional é ignorado&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;É a pegadinha clássica: o &lt;code&gt;@Transactional&lt;/code&gt; está lá, o código compila, não há erro nem aviso, e a transação simplesmente não é aberta. A documentação do Spring lista três saídas, nesta ordem de preferência:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Evitar a self-invocation&lt;/strong&gt;, refatorando. Por exemplo, mover &lt;code&gt;salvar()&lt;/code&gt; para outro bean, que é chamado por &lt;code&gt;PedidoService&lt;/code&gt;. É a opção menos invasiva.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Injetar uma referência ao próprio bean&lt;/strong&gt; (&lt;em&gt;self injection&lt;/em&gt;) e chamar o método por ela. A referência injetada é o proxy, então o advice roda. No Spring Boot, referências circulares são proibidas por padrão desde a versão 2.6, e uma autoinjeção comum faz a aplicação falhar na subida com erro de ciclo entre beans. Marcar a dependência com &lt;code&gt;@Lazy&lt;/code&gt; resolve:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;PedidoService.java&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;Service&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;PedidoService&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;final&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; PedidoService self;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;PedidoService&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(@&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;Lazy&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; PedidoService &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;.self &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; self;   &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// referência ao proxy, não ao objeto real&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;importar&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(List&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;Pedido&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;pedidos&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (Pedido p &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; pedidos) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;self.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;salvar&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(p);   &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// passa pelo proxy: a transação é aberta&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;Transactional&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;salvar&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(Pedido &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) { &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;/* ... */&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;AopContext.currentProxy()&lt;/code&gt;&lt;/strong&gt;, que devolve o proxy atual. A documentação desaconselha fortemente: acopla a classe ao Spring AOP e exige configurar o proxy para ser exposto (&lt;code&gt;@EnableAspectJAutoProxy(exposeProxy = true)&lt;/code&gt;).&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Com weaving do AspectJ (em compilação ou no carregamento das classes) o problema não existe, porque o advice fica dentro do próprio bytecode da classe, e não num proxy.&lt;/p&gt;
&lt;h2 id=&quot;5-jdk-dynamic-proxy-proxy-baseado-em-interface&quot;&gt;5. JDK Dynamic Proxy: proxy baseado em interface&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#5-jdk-dynamic-proxy-proxy-baseado-em-interface&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Faz parte do Java desde a versão 1.3 (&lt;code&gt;java.lang.reflect.Proxy&lt;/code&gt; + &lt;code&gt;InvocationHandler&lt;/code&gt;). Gera, em tempo de execução, uma classe que &lt;strong&gt;implementa as interfaces&lt;/strong&gt; informadas. Toda chamada a um método do proxy é redirecionada para o método &lt;code&gt;invoke(Object proxy, Method method, Object[] args)&lt;/code&gt; do handler, que decide o que fazer.&lt;/p&gt;
&lt;p&gt;Exemplo em Java puro (sem Spring) de um proxy que loga antes e depois de cada chamada:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;ProxyPuro.java&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; java.lang.reflect.InvocationHandler;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; java.lang.reflect.InvocationTargetException;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; java.lang.reflect.Method;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; java.lang.reflect.Proxy;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;ProxyPuro&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;main&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;[] &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;args&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;Servico alvo &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;ServicoImpl&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;Servico proxy &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (Servico) Proxy.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;newProxyInstance&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;Servico.class.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;getClassLoader&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; Class&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&gt;[] { Servico.class },&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;LogHandler&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(alvo));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;proxy.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;executar&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;x&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// ANTES de executar&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// executando: x&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// DEPOIS de executar&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;interface&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;Servico&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;executar&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(String &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;dado&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;ServicoImpl&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;implements&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;Servico&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;executar&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(String &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;dado&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;System.out.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;executando: &quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; dado);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;LogHandler&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;implements&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;InvocationHandler&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;final&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; Object alvo;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;LogHandler&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(Object &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;alvo&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) { &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;.alvo &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; alvo; }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;Override&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; Object &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;invoke&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(Object &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;proxy&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, Method &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;metodo&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;Object&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;[] &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;args&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;throws&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; Throwable {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;System.out.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;ANTES de &quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; metodo.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;getName&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;());&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;try&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; metodo.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;invoke&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(alvo, args);   &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// delega para o objeto real&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;catch&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (InvocationTargetException &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;throw&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; e.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;getCause&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;();                 &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// repassa a exceção original do alvo&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;finally&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;System.out.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;DEPOIS de &quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; metodo.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;getName&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;());&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;O arquivo roda direto com &lt;code&gt;java ProxyPuro.java&lt;/code&gt;. O &lt;code&gt;catch&lt;/code&gt; de &lt;code&gt;InvocationTargetException&lt;/code&gt; importa: a reflection embrulha qualquer exceção lançada pelo alvo, e sem desembrulhar quem chama o proxy receberia uma exceção diferente da original.&lt;/p&gt;
&lt;p&gt;Características práticas:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Exige que o alvo implemente pelo menos uma interface&lt;/strong&gt;, e só os métodos declarados nas interfaces passam pelo proxy.&lt;/li&gt;
&lt;li&gt;O proxy &lt;strong&gt;é do tipo da interface, nunca da classe concreta&lt;/strong&gt;. No Spring, isso significa que injetar o bean pela classe concreta falha na subida da aplicação: se &lt;code&gt;PedidoServiceImpl&lt;/code&gt; implementa &lt;code&gt;PedidoService&lt;/code&gt;, o proxy é um &lt;code&gt;PedidoService&lt;/code&gt;, mas não um &lt;code&gt;PedidoServiceImpl&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Não precisa de biblioteca externa: é parte do JDK.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No Spring Framework, continua sendo o padrão&lt;/strong&gt; quando o bean implementa alguma interface.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;6-cglib-proxy-via-subclasse&quot;&gt;6. CGLIB: proxy via subclasse&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#6-cglib-proxy-via-subclasse&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;CGLIB (&lt;em&gt;Code Generation Library&lt;/em&gt;) gera bytecode: cria em tempo de execução uma &lt;strong&gt;subclasse&lt;/strong&gt; da classe alvo e sobrescreve os métodos para inserir os advices. O Spring traz o CGLIB reempacotado dentro do &lt;code&gt;spring-core&lt;/code&gt;, sem dependência separada.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Não precisa de interface&lt;/strong&gt;: funciona com qualquer classe concreta.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Não intercepta métodos &lt;code&gt;final&lt;/code&gt;&lt;/strong&gt; (não dá para sobrescrever) e &lt;strong&gt;não gera proxy de classes &lt;code&gt;final&lt;/code&gt;&lt;/strong&gt; (não dá para estender). Métodos &lt;code&gt;private&lt;/code&gt; também ficam de fora.&lt;/li&gt;
&lt;li&gt;O construtor do alvo &lt;strong&gt;não é chamado duas vezes&lt;/strong&gt;: o Spring cria a instância do proxy via Objenesis, uma biblioteca que instancia objetos sem executar construtor.&lt;/li&gt;
&lt;li&gt;Pode esbarrar no sistema de módulos do Java: com a aplicação no &lt;em&gt;module path&lt;/em&gt;, por exemplo, não dá para gerar proxy CGLIB de uma classe do pacote &lt;code&gt;java.lang&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;quando-o-spring-usa-cada-um&quot;&gt;Quando o Spring usa cada um&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#quando-o-spring-usa-cada-um&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Spring Framework puro:&lt;/strong&gt; se o bean implementa pelo menos uma interface, usa JDK Dynamic Proxy; se não implementa nenhuma, usa CGLIB. Para forçar CGLIB, use &lt;code&gt;proxyTargetClass = true&lt;/code&gt; em &lt;code&gt;@EnableAspectJAutoProxy&lt;/code&gt;, &lt;code&gt;@EnableTransactionManagement&lt;/code&gt; e anotações parecidas. Essas configurações são unificadas: se uma delas força CGLIB, vale para todas.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Spring Boot:&lt;/strong&gt; desde a &lt;strong&gt;versão 2.0&lt;/strong&gt;, usa &lt;strong&gt;CGLIB por padrão&lt;/strong&gt;, mesmo quando o bean implementa interface, e isso vale também para &lt;code&gt;@Transactional&lt;/code&gt; e os demais recursos baseados em proxy. A propriedade é &lt;code&gt;spring.aop.proxy-target-class&lt;/code&gt;, com padrão &lt;code&gt;true&lt;/code&gt;. Com o AspectJ no classpath, o Spring Boot também já habilita os aspects sozinho, sem precisar de &lt;code&gt;@EnableAspectJAutoProxy&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Por bean (Spring Framework 7.0+):&lt;/strong&gt; a anotação &lt;code&gt;@Proxyable&lt;/code&gt; num &lt;code&gt;@Bean&lt;/code&gt; ou &lt;code&gt;@Component&lt;/code&gt; escolhe o tipo de proxy daquele bean (&lt;code&gt;@Proxyable(INTERFACES)&lt;/code&gt; ou &lt;code&gt;@Proxyable(TARGET_CLASS)&lt;/code&gt;), sobrepondo o padrão global.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Na prática, a diferença aparece em dois casos, os mesmos que a documentação do Spring cita como motivo para forçar CGLIB: quando é preciso aplicar advice num método que não está declarado em interface nenhuma e quando o bean precisa ser usado pelo tipo da classe concreta. Com proxy de subclasse, os dois funcionam; com JDK Dynamic Proxy, o advice fica de fora no primeiro e a injeção falha no segundo.&lt;/p&gt;
&lt;h2 id=&quot;7-comparativo-rápido&quot;&gt;7. Comparativo rápido&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#7-comparativo-rápido&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;table-wrap&quot;&gt;

















































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;JDK Dynamic Proxy&lt;/th&gt;&lt;th&gt;CGLIB&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Como funciona&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Classe gerada que implementa as interfaces&lt;/td&gt;&lt;td&gt;Subclasse gerada da classe alvo&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Exige interface?&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Sim&lt;/td&gt;&lt;td&gt;Não&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Métodos interceptados&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Públicos declarados em interface&lt;/td&gt;&lt;td&gt;&lt;code&gt;public&lt;/code&gt; e &lt;code&gt;protected&lt;/code&gt; (e de pacote, se necessário); nunca &lt;code&gt;final&lt;/code&gt; ou &lt;code&gt;private&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Classe &lt;code&gt;final&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Funciona (o proxy não estende a classe)&lt;/td&gt;&lt;td&gt;Não funciona (não dá para estender)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Injetar/converter para&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Só a interface&lt;/td&gt;&lt;td&gt;Classe concreta ou interface&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Origem&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;JDK (&lt;code&gt;java.lang.reflect.Proxy&lt;/code&gt;)&lt;/td&gt;&lt;td&gt;Biblioteca reempacotada no &lt;code&gt;spring-core&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Padrão no Spring Framework&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Quando o bean implementa interface&lt;/td&gt;&lt;td&gt;Quando o bean não implementa interface&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Padrão no Spring Boot 2.0+&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Só com &lt;code&gt;spring.aop.proxy-target-class=false&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Sim, com ou sem interface&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;
&lt;h2 id=&quot;8-escrevendo-um-aspect-custom&quot;&gt;8. Escrevendo um aspect custom&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#8-escrevendo-um-aspect-custom&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Quando você usa &lt;code&gt;@Transactional&lt;/code&gt;, &lt;code&gt;@Async&lt;/code&gt; ou &lt;code&gt;@Cacheable&lt;/code&gt;, está usando recursos &lt;strong&gt;prontos&lt;/strong&gt; do Spring, construídos sobre essa mesma infraestrutura de proxy. Um &lt;strong&gt;aspect custom&lt;/strong&gt; é um aspect que você mesmo escreve para uma preocupação transversal do seu sistema.&lt;/p&gt;
&lt;p&gt;Exemplo: medir o tempo de execução de todo método público dos serviços.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;TimingAspect.java&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; org.aspectj.lang.ProceedingJoinPoint;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; org.aspectj.lang.annotation.Around;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; org.aspectj.lang.annotation.Aspect;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; org.aspectj.lang.annotation.Pointcut;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; org.springframework.stereotype.Component;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;Aspect&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;Component&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;TimingAspect&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// Pointcut: todos os métodos públicos das classes anotadas&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// com @Service no pacote com.exemplo e subpacotes&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;Pointcut&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;execution(public * com.exemplo..*(..)) &quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;+&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;              &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;&amp;#x26;&amp;#x26; within(@org.springframework.stereotype.Service *)&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;servicos&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;() {}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;Around&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;servicos()&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; Object &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;medir&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(ProceedingJoinPoint &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;pjp&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;throws&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; Throwable {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;long&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; inicio &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; System.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;nanoTime&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;try&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; pjp.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;proceed&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;();  &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// chama o método real&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;finally&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;long&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; ms &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (System.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;nanoTime&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; inicio) &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79B8FF;--1:#005CC5&quot;&gt;1_000_000&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;String nome &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; pjp.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;getSignature&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;toShortString&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;System.out.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(nome &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot; levou &quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; ms &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;ms&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Pontos a notar:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;@Aspect&lt;/code&gt; sozinho não registra o bean; o &lt;code&gt;@Component&lt;/code&gt; é o que faz o component scan encontrar a classe.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;execution(public * com.exemplo..*(..))&lt;/code&gt; casa com qualquer método público, de qualquer retorno e com quaisquer argumentos, em &lt;code&gt;com.exemplo&lt;/code&gt; e subpacotes. &lt;code&gt;within(@...Service *)&lt;/code&gt; restringe às classes anotadas com &lt;code&gt;@Service&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Aqui &lt;code&gt;@Around&lt;/code&gt; é justificado: é preciso marcar o tempo antes e calcular depois, na mesma execução. Por isso o método retorna &lt;code&gt;Object&lt;/code&gt; e devolve o resultado de &lt;code&gt;proceed()&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Com isso, todo &lt;code&gt;@Service&lt;/code&gt; do pacote passa a ter medição de tempo sem alterar uma linha das classes de negócio. É esse o ganho concreto do AOP. E vale a pegadinha da seção 4: um serviço que chama o próprio método via &lt;code&gt;this&lt;/code&gt; não terá essa chamada interna medida.&lt;/p&gt;
&lt;p&gt;Dependência necessária no Spring Boot 4:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;pom.xml&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;xml&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#85E89D;--1:#1E7734&quot;&gt;dependency&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#85E89D;--1:#1E7734&quot;&gt;groupId&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&gt;org.springframework.boot&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#85E89D;--1:#1E7734&quot;&gt;groupId&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#85E89D;--1:#1E7734&quot;&gt;artifactId&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&gt;spring-boot-starter-aspectj&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#85E89D;--1:#1E7734&quot;&gt;artifactId&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#85E89D;--1:#1E7734&quot;&gt;dependency&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Até o Spring Boot 3.x, o nome do starter era &lt;code&gt;spring-boot-starter-aop&lt;/code&gt;; no 4.0 ele foi renomeado para &lt;code&gt;spring-boot-starter-aspectj&lt;/code&gt;. O starter traz o &lt;code&gt;aspectjweaver&lt;/code&gt;, a biblioteca do AspectJ que fornece as anotações (&lt;code&gt;@Aspect&lt;/code&gt;, &lt;code&gt;@Around&lt;/code&gt;…) e interpreta as expressões de pointcut. O weaving continua sendo do Spring AOP, em tempo de execução via proxy: nem o compilador nem o weaver do AspectJ entram em ação. O guia de migração sugere revisar se o starter é mesmo necessário: ele só faz falta se a aplicação (ou alguma biblioteca, como o &lt;code&gt;@Timed&lt;/code&gt; do Micrometer) usa as anotações do pacote &lt;code&gt;org.aspectj.lang.annotation&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;9-cuidados-práticos&quot;&gt;9. Cuidados práticos&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#9-cuidados-práticos&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Self-invocation não passa pelo proxy.&lt;/strong&gt; Se &lt;code&gt;metodoA()&lt;/code&gt; chama &lt;code&gt;this.metodoB()&lt;/code&gt; na mesma classe, o advice de &lt;code&gt;metodoB()&lt;/code&gt; não roda. Prefira separar em outro bean; como alternativa, injete o próprio bean com &lt;code&gt;@Lazy&lt;/code&gt; e chame por ele (seção 4).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Métodos &lt;code&gt;private&lt;/code&gt; e &lt;code&gt;final&lt;/code&gt; nunca recebem advice&lt;/strong&gt;, e com JDK Dynamic Proxy só os métodos de interface. Deixe as chamadas que precisam de advice em métodos públicos.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;bean.getClass()&lt;/code&gt; retorna a classe do proxy&lt;/strong&gt;, não a real (ex.: &lt;code&gt;PedidoService$$SpringCGLIB$$0&lt;/code&gt;). Para reflection e leitura de anotações, use &lt;code&gt;AopUtils.getTargetClass(bean)&lt;/code&gt;, assunto do post &lt;a href=&quot;https://cesarschutz.com.br/posts/aoputils-gettargetclass/&quot;&gt;AopUtils.getTargetClass(): desembrulhando os proxies do Spring&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Forçar JDK Dynamic Proxy no Spring Boot:&lt;/strong&gt; &lt;code&gt;spring.aop.proxy-target-class=false&lt;/code&gt;. Em geral não compensa: qualquer injeção pela classe concreta passa a falhar na subida.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Desempenho:&lt;/strong&gt; cada chamada interceptada percorre a cadeia de advices antes de chegar ao método real. Em caminhos muito quentes, meça antes de concluir se o custo importa.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;fontes&quot;&gt;Fontes&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#fontes&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Spring Framework Reference — &lt;a href=&quot;https://docs.spring.io/spring-framework/reference/core/aop/introduction-defn.html&quot;&gt;AOP Concepts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Spring Framework Reference — &lt;a href=&quot;https://docs.spring.io/spring-framework/reference/core/aop/introduction-proxies.html&quot;&gt;AOP Proxies&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Spring Framework Reference — &lt;a href=&quot;https://docs.spring.io/spring-framework/reference/core/aop/proxying.html&quot;&gt;Proxying Mechanisms&lt;/a&gt; (JDK x CGLIB, &lt;code&gt;proxyTargetClass&lt;/code&gt;, &lt;code&gt;@Proxyable&lt;/code&gt;, self-invocation)&lt;/li&gt;
&lt;li&gt;Spring Framework Reference — &lt;a href=&quot;https://docs.spring.io/spring-framework/reference/core/aop/ataspectj.html&quot;&gt;@AspectJ support&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Spring Framework Reference — &lt;a href=&quot;https://docs.spring.io/spring-framework/reference/core/aop/ataspectj/pointcuts.html&quot;&gt;Declaring a Pointcut&lt;/a&gt; (métodos interceptados por tipo de proxy)&lt;/li&gt;
&lt;li&gt;Spring Framework Reference — &lt;a href=&quot;https://docs.spring.io/spring-framework/reference/core/aop/ataspectj/advice.html&quot;&gt;Declaring Advice&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Spring Framework Reference — &lt;a href=&quot;https://docs.spring.io/spring-framework/reference/core/beans/annotation-config/autowired.html&quot;&gt;Using @Autowired: Self Injection&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Spring Boot Reference — &lt;a href=&quot;https://docs.spring.io/spring-boot/reference/features/aop.html&quot;&gt;Aspect-Oriented Programming&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Spring Boot Reference — &lt;a href=&quot;https://docs.spring.io/spring-boot/appendix/application-properties/index.html&quot;&gt;Common Application Properties&lt;/a&gt; (&lt;code&gt;spring.aop.proxy-target-class&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Spring Boot Wiki — &lt;a href=&quot;https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.0-Migration-Guide&quot;&gt;Spring Boot 2.0 Migration Guide&lt;/a&gt; (CGLIB como padrão)&lt;/li&gt;
&lt;li&gt;Spring Boot Wiki — &lt;a href=&quot;https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.6-Release-Notes&quot;&gt;Spring Boot 2.6 Release Notes&lt;/a&gt; (referências circulares proibidas por padrão)&lt;/li&gt;
&lt;li&gt;Spring Boot Wiki — &lt;a href=&quot;https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-4.0-Migration-Guide&quot;&gt;Spring Boot 4.0 Migration Guide&lt;/a&gt; (renomeação para &lt;code&gt;spring-boot-starter-aspectj&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Java SE 25 API — &lt;a href=&quot;https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/reflect/Proxy.html&quot;&gt;java.lang.reflect.Proxy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Baeldung — &lt;a href=&quot;https://www.baeldung.com/java-dynamic-proxies&quot;&gt;Dynamic Proxies in Java&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Baeldung — &lt;a href=&quot;https://www.baeldung.com/spring-aop-pointcut-tutorial&quot;&gt;Introduction to Pointcut Expressions in Spring&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>Java</category><category>Spring</category><category>AOP</category></item><item><title>AopUtils.getTargetClass() — desembrulhando os proxies do Spring</title><link>https://cesarschutz.com.br/posts/aoputils-gettargetclass/</link><guid isPermaLink="true">https://cesarschutz.com.br/posts/aoputils-gettargetclass/</guid><description>Com o bean envolto em proxy, bean.getClass() devolve a classe do proxy e a leitura de anotações falha. Como AopUtils.getTargetClass() recupera a classe real e quando usar ultimateTargetClass().</description><pubDate>Tue, 19 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;No Spring, anotações como &lt;code&gt;@Transactional&lt;/code&gt;, &lt;code&gt;@Async&lt;/code&gt;, &lt;code&gt;@Cacheable&lt;/code&gt; e &lt;code&gt;@PreAuthorize&lt;/code&gt; só funcionam porque o container troca o bean original por um &lt;strong&gt;proxy&lt;/strong&gt;: um objeto gerado em tempo de execução que intercepta as chamadas, executa a lógica extra e repassa a chamada ao objeto real (o modelo completo está no post &lt;a href=&quot;https://cesarschutz.com.br/posts/aop-jdk-proxy-cglib/&quot;&gt;AOP no Spring — JDK Dynamic Proxy, CGLIB e aspects custom&lt;/a&gt;). O efeito colateral é que &lt;code&gt;bean.getClass()&lt;/code&gt; deixa de retornar a sua classe e passa a retornar a classe do proxy.&lt;/p&gt;
&lt;p&gt;Neste post você vai ver por que isso quebra reflection, logs e mapas indexados por classe, como &lt;strong&gt;&lt;code&gt;AopUtils.getTargetClass(bean)&lt;/code&gt;&lt;/strong&gt; recupera a classe real e quando é preciso recorrer a &lt;code&gt;AopProxyUtils.ultimateTargetClass()&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;o-que-o-aop-faz-pelo-seu-código-na-prática&quot;&gt;O que o AOP faz pelo seu código, na prática&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#o-que-o-aop-faz-pelo-seu-código-na-prática&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Sem AOP, as preocupações transversais (transação, segurança, métricas, que não fazem parte da regra de negócio) se espalham pelo método. Em um esboço simplificado:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://cesarschutz.com.br/_astro/ec.bzl1c.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;https://cesarschutz.com.br/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;Sem AOP&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; Pedido &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;criar&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(Pedido p) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;long&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; inicio &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; System.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;currentTimeMillis&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;tx.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;begin&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;try&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;user.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;hasRole&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;ADMIN&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;)) &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;throw&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;AccessDenied&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;log.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;info&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;criando pedido {}&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, p);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; salvo &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; repo.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;save&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(p);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;tx.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;commit&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; salvo;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;catch&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; (Exception &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;tx.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;rollback&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;throw&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; e;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;finally&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;metrics.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;criar&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, System.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;currentTimeMillis&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; inicio);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Com AOP, o método volta a falar só de negócio:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;Com AOP&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;Transactional&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;PreAuthorize&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;hasRole(&apos;ADMIN&apos;)&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;Timed&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;criar&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// Micrometer; exige o TimedAspect registrado&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; Pedido &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;criar&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(Pedido p) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;log.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;info&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;criando pedido {}&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;, p);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; repo.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;save&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(p);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Cada anotação é atendida por um interceptor (o &lt;em&gt;advice&lt;/em&gt;) que o container aplica ao bean. É exatamente por isso que o objeto injetado &lt;strong&gt;não é&lt;/strong&gt; uma instância da sua classe: é o proxy que executa esses interceptores antes de chamar o seu código.&lt;/p&gt;
&lt;h2 id=&quot;o-problema-beangetclass-devolve-a-classe-do-proxy&quot;&gt;O problema: &lt;code&gt;bean.getClass()&lt;/code&gt; devolve a classe do proxy&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#o-problema-beangetclass-devolve-a-classe-do-proxy&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;O Spring gera o proxy de duas formas:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;JDK Dynamic Proxy&lt;/strong&gt;: uma classe criada pela JVM que implementa as interfaces do bean. É o padrão do Spring Framework quando o bean implementa ao menos uma interface.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CGLIB&lt;/strong&gt;: uma subclasse da sua classe gerada em tempo de execução. É usada quando o bean não implementa interfaces e é o padrão no Spring Boot (&lt;code&gt;spring.aop.proxy-target-class=true&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Por isso &lt;code&gt;getClass()&lt;/code&gt; devolve algo assim:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;txt&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#e1e4e8;--1:#24292e&quot;&gt;br.com.exemplo.MeuServico$$SpringCGLIB$$0   // CGLIB: subclasse de MeuServico&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#e1e4e8;--1:#24292e&quot;&gt;jdk.proxy2.$Proxy42                         // JDK: pacote e número variam&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Desde o Spring Framework 6.0, o nome das classes CGLIB usa o marcador &lt;code&gt;$$SpringCGLIB$$&lt;/code&gt; seguido de um contador (antes era um hash). No proxy JDK, a especificação só reserva o prefixo &lt;code&gt;$Proxy&lt;/code&gt;; o nome do pacote não é especificado.&lt;/p&gt;
&lt;p&gt;Isso quebra qualquer código que dependa da identidade da classe real:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Leitura de anotações via reflection.&lt;/strong&gt; A subclasse CGLIB só enxerga as anotações de classe marcadas com &lt;code&gt;@Inherited&lt;/code&gt; (como &lt;code&gt;@Transactional&lt;/code&gt;). Anotações sem &lt;code&gt;@Inherited&lt;/code&gt;, como uma anotação sua, não aparecem, e as anotações de método também não, porque o proxy sobrescreve os métodos sem copiá-las. O proxy JDK não enxerga nenhuma anotação da classe alvo.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Logging&lt;/strong&gt; com &lt;code&gt;getClass().getSimpleName()&lt;/code&gt;: o log mostra &lt;code&gt;MeuServico$$SpringCGLIB$$0&lt;/code&gt; ou &lt;code&gt;$Proxy42&lt;/code&gt; no lugar de &lt;code&gt;MeuServico&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mapas do tipo &lt;code&gt;Map&amp;#x3C;Class&amp;#x3C;?&gt;, Handler&gt;&lt;/code&gt;&lt;/strong&gt;: &lt;code&gt;handlers.get(bean.getClass())&lt;/code&gt; não encontra a entrada registrada com &lt;code&gt;MeuServico.class&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Código de infraestrutura que descobre metadados pela classe&lt;/strong&gt;, como um &lt;code&gt;BeanPostProcessor&lt;/code&gt; próprio ou um registro de listeners: sofre dos mesmos problemas.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://cesarschutz.com.br/posts/aoputils-gettargetclass/getclass-vs-gettargetclass.svg&quot; alt=&quot;bean.getClass() devolve a classe do proxy MeuServicoSpringCGLIB0; AopUtils.getTargetClass(bean) atravessa o proxy e devolve MeuServico&quot;&gt;&lt;/p&gt;
&lt;p&gt;O diagrama resume a diferença: o proxy envolve o objeto real; &lt;code&gt;getClass()&lt;/code&gt; para na camada de fora, e &lt;code&gt;getTargetClass()&lt;/code&gt; atravessa essa camada e devolve a classe que você escreveu.&lt;/p&gt;
&lt;h2 id=&quot;o-utilitário-aoputilsgettargetclassobject&quot;&gt;O utilitário: &lt;code&gt;AopUtils.getTargetClass(Object)&lt;/code&gt;&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#o-utilitário-aoputilsgettargetclassobject&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Fica no pacote &lt;code&gt;org.springframework.aop.support&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; Class&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;&amp;#x3C;?&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;getTargetClass&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(Object candidate)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Segundo o Javadoc, o método determina a classe alvo de um bean que pode ser um proxy AOP: devolve a classe alvo quando é proxy e a própria classe do objeto nos demais casos, &lt;strong&gt;nunca &lt;code&gt;null&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Como ele chega lá (código do Spring Framework 7.0.9):&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Se o objeto implementa &lt;code&gt;TargetClassAware&lt;/code&gt;, pergunta a ele qual é a classe alvo. Todo proxy Spring AOP implementa essa interface por meio de &lt;code&gt;Advised&lt;/code&gt;, a menos que tenha sido criado com a opção &lt;code&gt;opaque&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Se não obteve resposta, usa a superclasse quando o objeto é um proxy CGLIB e &lt;code&gt;getClass()&lt;/code&gt; nos demais casos.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Na prática:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Se o bean &lt;strong&gt;não&lt;/strong&gt; é proxy, retorna &lt;code&gt;bean.getClass()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Se é proxy &lt;strong&gt;CGLIB&lt;/strong&gt; ou &lt;strong&gt;JDK&lt;/strong&gt;, retorna a classe do objeto real que o proxy envolve.&lt;/li&gt;
&lt;li&gt;Se é um &lt;strong&gt;proxy de proxy&lt;/strong&gt;, desce &lt;strong&gt;apenas um nível&lt;/strong&gt; e retorna a classe do proxy interno (por exemplo, &lt;code&gt;MeuServico$$SpringCGLIB$$0&lt;/code&gt;). Para chegar ao fundo, use &lt;code&gt;AopProxyUtils.ultimateTargetClass()&lt;/code&gt;, descrito mais abaixo.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Nunca retorna &lt;code&gt;null&lt;/code&gt;&lt;/strong&gt;, garantia da API.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;exemplo-prático&quot;&gt;Exemplo prático&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#exemplo-prático&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Como &lt;code&gt;MeuServico&lt;/code&gt; não implementa interface, o Spring cria um proxy CGLIB por causa do &lt;code&gt;@Transactional&lt;/code&gt;. A anotação &lt;code&gt;@Auditavel&lt;/code&gt; foi criada sem &lt;code&gt;@Inherited&lt;/code&gt; para mostrar a diferença:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;Auditavel, MeuServico e Inspetor (um arquivo por tipo)&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; org.springframework.aop.support.AopUtils;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; org.springframework.transaction.annotation.Transactional;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// demais imports omitidos&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;Retention&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(RetentionPolicy.RUNTIME)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;Target&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(ElementType.TYPE)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; @&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;interface&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;Auditavel&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; {} &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// sem @Inherited&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;Service&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;Auditavel&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;MeuServico&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;Transactional&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;processar&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;() { &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;/* ... */&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;Component&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;Inspetor&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;inspecionar&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(Object &lt;/span&gt;&lt;span style=&quot;--0:#FFAB70;--1:#AE4B07&quot;&gt;bean&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;throws&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; NoSuchMethodException {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;System.out.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(bean.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;getClass&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;getName&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;());&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// br.com.exemplo.MeuServico$$SpringCGLIB$$0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;Class&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;&gt; alvo &lt;/span&gt;&lt;span style=&quot;--0:#F97583;--1:#BF3441&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt; AopUtils.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;getTargetClass&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(bean);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;System.out.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(alvo.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;getName&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;());&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// br.com.exemplo.MeuServico&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// Anotação de classe sem @Inherited&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;bean.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;getClass&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;isAnnotationPresent&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(Auditavel.class); &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// false&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;alvo.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;isAnnotationPresent&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(Auditavel.class);            &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// true&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// Anotação de método&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;bean.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;getClass&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;getMethod&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;processar&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;isAnnotationPresent&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(Transactional.class);    &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// false&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;alvo.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;getMethod&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9ECBFF;--1:#032F62&quot;&gt;&quot;processar&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#B392F0;--1:#6F42C1&quot;&gt;isAnnotationPresent&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;(Transactional.class);    &lt;/span&gt;&lt;span style=&quot;--0:#99A0A6;--1:#616972&quot;&gt;// true&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E1E4E8;--1:#24292E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Use a classe alvo só para ler metadados. Para &lt;strong&gt;chamar&lt;/strong&gt; métodos, continue usando o próprio bean: é o proxy que aplica a transação, o cache e a segurança.&lt;/p&gt;
&lt;h2 id=&quot;métodos-relacionados&quot;&gt;Métodos relacionados&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#métodos-relacionados&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;O próprio &lt;code&gt;AopUtils&lt;/code&gt; tem três métodos para descobrir que tipo de objeto você recebeu. Todos verificam também se o objeto implementa &lt;code&gt;SpringProxy&lt;/code&gt;, ou seja, respondem &lt;code&gt;true&lt;/code&gt; só para proxies criados pelo Spring AOP:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;isAopProxy(Object)&lt;/code&gt;: &lt;code&gt;true&lt;/code&gt; se o objeto é um proxy Spring AOP, JDK ou CGLIB.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;isCglibProxy(Object)&lt;/code&gt;: &lt;code&gt;true&lt;/code&gt; se é um proxy CGLIB.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;isJdkDynamicProxy(Object)&lt;/code&gt;: &lt;code&gt;true&lt;/code&gt; se é um JDK Dynamic Proxy.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Em outras classes utilitárias:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;AopProxyUtils.ultimateTargetClass(Object)&lt;/code&gt;&lt;/strong&gt; (pacote &lt;code&gt;org.springframework.aop.framework&lt;/code&gt;): desce por &lt;strong&gt;qualquer número de proxies aninhados&lt;/strong&gt; até a classe final. Só atravessa um nível quando consegue fazer isso sem efeitos colaterais, isto é, quando o alvo é um singleton guardado em um &lt;code&gt;SingletonTargetSource&lt;/code&gt; (o &lt;code&gt;TargetSource&lt;/code&gt; é o componente que entrega ao proxy o objeto real). Com outros &lt;code&gt;TargetSource&lt;/code&gt;s (lazy, pool, protótipo, hot swap), para naquele nível e devolve a classe informada por ele. Também nunca retorna &lt;code&gt;null&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;ClassUtils.getUserClass(Object)&lt;/code&gt;&lt;/strong&gt; (pacote &lt;code&gt;org.springframework.util&lt;/code&gt;): devolve a classe original quando a classe do objeto é uma subclasse gerada pelo CGLIB (nome com &lt;code&gt;$$&lt;/code&gt;). Não reconhece proxy JDK, que continua como &lt;code&gt;$Proxy42&lt;/code&gt;. Tem também a versão &lt;code&gt;getUserClass(Class&amp;#x3C;?&gt;)&lt;/code&gt;, útil quando você só tem a classe em mãos.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;O diagrama abaixo mostra a diferença em um proxy JDK que envolve um proxy CGLIB:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cesarschutz.com.br/posts/aoputils-gettargetclass/proxy-aninhado.svg&quot; alt=&quot;getTargetClass desce um nível e para no proxy interno MeuServicoSpringCGLIB0; ultimateTargetClass desce até MeuServico&quot;&gt;&lt;/p&gt;
&lt;p&gt;Resumo do comportamento, conferido no Spring Framework 7.0.9:&lt;/p&gt;
&lt;div class=&quot;table-wrap&quot;&gt;




























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Método&lt;/th&gt;&lt;th&gt;Proxy CGLIB&lt;/th&gt;&lt;th&gt;Proxy JDK&lt;/th&gt;&lt;th&gt;Proxy de proxy&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;AopUtils.getTargetClass&lt;/code&gt;&lt;/td&gt;&lt;td&gt;classe real&lt;/td&gt;&lt;td&gt;classe real&lt;/td&gt;&lt;td&gt;classe do proxy interno&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;AopProxyUtils.ultimateTargetClass&lt;/code&gt;&lt;/td&gt;&lt;td&gt;classe real&lt;/td&gt;&lt;td&gt;classe real&lt;/td&gt;&lt;td&gt;classe real (alvos singleton)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;ClassUtils.getUserClass&lt;/code&gt;&lt;/td&gt;&lt;td&gt;classe real&lt;/td&gt;&lt;td&gt;classe do proxy (&lt;code&gt;$Proxy…&lt;/code&gt;)&lt;/td&gt;&lt;td&gt;depende do tipo de cada proxy (não use)&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;
&lt;h2 id=&quot;regra-prática&quot;&gt;Regra prática&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#regra-prática&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Sempre que for inspecionar um bean Spring por reflection (ler anotações, comparar tipos, registrar em mapa por classe, logar um nome legível), use &lt;code&gt;AopUtils.getTargetClass(bean)&lt;/code&gt; em vez de &lt;code&gt;bean.getClass()&lt;/code&gt;. Se o bean puder estar envolvido por mais de um proxy, prefira &lt;code&gt;AopProxyUtils.ultimateTargetClass(bean)&lt;/code&gt;. Não custa nada e evita bugs que só aparecem meses depois, quando alguém adiciona um &lt;code&gt;@Transactional&lt;/code&gt; ao serviço e o proxy passa a existir.&lt;/p&gt;
&lt;h2 id=&quot;fontes&quot;&gt;Fontes&lt;a class=&quot;heading-anchor&quot; aria-label=&quot;Link para esta seção&quot; href=&quot;#fontes&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Spring Framework Reference — &lt;a href=&quot;https://docs.spring.io/spring-framework/reference/core/aop/proxying.html&quot;&gt;Proxying Mechanisms&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Spring Framework Reference — &lt;a href=&quot;https://docs.spring.io/spring-framework/reference/core/aop/introduction-proxies.html&quot;&gt;AOP Proxies&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Javadoc — &lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/aop/support/AopUtils.html&quot;&gt;AopUtils&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Javadoc — &lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/aop/framework/AopProxyUtils.html&quot;&gt;AopProxyUtils&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Javadoc — &lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/util/ClassUtils.html&quot;&gt;ClassUtils&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Javadoc — &lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/aop/TargetClassAware.html&quot;&gt;TargetClassAware&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Javadoc — &lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/transaction/annotation/Transactional.html&quot;&gt;Transactional&lt;/a&gt; (declarada com &lt;code&gt;@Inherited&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Código-fonte do Spring Framework 7.0.9 — &lt;a href=&quot;https://github.com/spring-projects/spring-framework/blob/v7.0.9/spring-aop/src/main/java/org/springframework/aop/support/AopUtils.java&quot;&gt;AopUtils.java&lt;/a&gt;, &lt;a href=&quot;https://github.com/spring-projects/spring-framework/blob/v7.0.9/spring-aop/src/main/java/org/springframework/aop/framework/AopProxyUtils.java&quot;&gt;AopProxyUtils.java&lt;/a&gt; e &lt;a href=&quot;https://github.com/spring-projects/spring-framework/blob/v7.0.9/spring-core/src/main/java/org/springframework/cglib/core/SpringNamingPolicy.java&quot;&gt;SpringNamingPolicy.java&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Spring Boot — &lt;a href=&quot;https://docs.spring.io/spring-boot/appendix/application-properties/index.html&quot;&gt;Common Application Properties&lt;/a&gt; (&lt;code&gt;spring.aop.proxy-target-class&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Java SE 21 API — &lt;a href=&quot;https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/reflect/Proxy.html&quot;&gt;java.lang.reflect.Proxy&lt;/a&gt; e &lt;a href=&quot;https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/annotation/Inherited.html&quot;&gt;java.lang.annotation.Inherited&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Micrometer — &lt;a href=&quot;https://docs.micrometer.io/micrometer/reference/concepts/timers.html&quot;&gt;Timers&lt;/a&gt; (&lt;code&gt;@Timed&lt;/code&gt; e &lt;code&gt;TimedAspect&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>Java</category><category>Spring</category><category>AOP</category></item><item><title>AtomicBoolean — o sinalizador thread-safe da parada graciosa</title><link>https://cesarschutz.com.br/posts/atomicboolean-parada-graciosa/</link><guid isPermaLink="true">https://cesarschutz.com.br/posts/atomicboolean-parada-graciosa/</guid><description>Por que um boolean comum pode não ser visto por outra thread, quando volatile basta, por que preferir AtomicBoolean e como ligar o SIGTERM a um job sem encerrar a JVM no meio de um lote.</description><pubDate>Tue, 19 May 2026 00:00:00 GMT</pubDate><category>Java</category><category>Concorrência</category><category>Kubernetes</category><category>JVM</category></item><item><title>Gradle — quando usar implementation, api, compileOnly e as demais configurações</title><link>https://cesarschutz.com.br/posts/gradle-tipos-de-dependencia/</link><guid isPermaLink="true">https://cesarschutz.com.br/posts/gradle-tipos-de-dependencia/</guid><description>Cada configuração de dependência do Gradle alimenta um classpath: compilação, execução, processadores de anotação ou testes. Guia para bibliotecas e starters Spring Boot, com o papel do platform (BOM).</description><pubDate>Tue, 19 May 2026 00:00:00 GMT</pubDate><category>Java</category><category>Gradle</category><category>Spring</category></item><item><title>Kubernetes CronJob — concorrência, retries e tempo máximo de execução</title><link>https://cesarschutz.com.br/posts/kubernetes-cronjob-concorrencia/</link><guid isPermaLink="true">https://cesarschutz.com.br/posts/kubernetes-cronjob-concorrencia/</guid><description>Os campos que protegem rotinas agendadas: concurrencyPolicy, startingDeadlineSeconds, activeDeadlineSeconds, backoffLimit, restartPolicy e timeZone, e o que eles não garantem.</description><pubDate>Tue, 19 May 2026 00:00:00 GMT</pubDate><category>DevOps</category><category>Kubernetes</category><category>Concorrência</category></item><item><title>Logging estruturado em Spring Boot — LogstashEncoder vs o suporte nativo do 3.4+</title><link>https://cesarschutz.com.br/posts/logging-estruturado-spring-boot/</link><guid isPermaLink="true">https://cesarschutz.com.br/posts/logging-estruturado-spring-boot/</guid><description>Cada log como uma linha JSON pesquisável: o caminho clássico com LogstashEncoder e o suporte nativo do Spring Boot 3.4+ (ECS, Logstash e GELF), com saídas reais, comparativo e critério de escolha.</description><pubDate>Tue, 19 May 2026 00:00:00 GMT</pubDate><category>Observabilidade</category><category>Spring</category><category>Logs</category><category>Trade-offs</category></item><item><title>SIGTERM e SIGKILL — o ciclo de término de um pod no Kubernetes</title><link>https://cesarschutz.com.br/posts/sigterm-sigkill-kubernetes/</link><guid isPermaLink="true">https://cesarschutz.com.br/posts/sigterm-sigkill-kubernetes/</guid><description>Como o Kubernetes encerra um pod: SIGTERM, SIGKILL e grace period, a corrida com os endpoints que o preStop resolve, exit codes, o graceful shutdown do Spring Boot e a pegadinha do PID 1.</description><pubDate>Tue, 19 May 2026 00:00:00 GMT</pubDate><category>DevOps</category><category>Kubernetes</category><category>Spring</category></item><item><title>Wide events e canonical log lines — a evolução do logging estruturado</title><link>https://cesarschutz.com.br/posts/wide-events-canonical-log-lines/</link><guid isPermaLink="true">https://cesarschutz.com.br/posts/wide-events-canonical-log-lines/</guid><description>Um evento rico em contexto por requisição, no lugar de dezenas de logs parciais: as canonical log lines da Stripe, cardinalidade e Observability 2.0, um filtro em Spring Boot e tail sampling.</description><pubDate>Tue, 19 May 2026 00:00:00 GMT</pubDate><category>Observabilidade</category><category>Logs</category><category>Spring</category></item><item><title>Overhead vs overkill — o custo de toda escolha e o exagero dela</title><link>https://cesarschutz.com.br/posts/overhead-vs-overkill/</link><guid isPermaLink="true">https://cesarschutz.com.br/posts/overhead-vs-overkill/</guid><description>Overhead é o custo extra que toda decisão técnica cobra; overkill é a solução desproporcional ao problema. As seis dimensões do overhead e um critério prático para reconhecer overengineering.</description><pubDate>Sat, 16 May 2026 00:00:00 GMT</pubDate><category>Arquitetura</category><category>Trade-offs</category><category>Microsserviços</category></item><item><title>JWT — a estrutura e o significado de cada campo</title><link>https://cesarschutz.com.br/posts/jwt-estrutura-e-campos/</link><guid isPermaLink="true">https://cesarschutz.com.br/posts/jwt-estrutura-e-campos/</guid><description>As três partes de um JWT, campo a campo: headers JOSE (alg, kid…), claims registradas (iss, sub, exp…), algoritmos de assinatura e cuidados de validação. O payload não é criptografado.</description><pubDate>Sun, 12 Apr 2026 00:00:00 GMT</pubDate><category>Segurança</category><category>JWT</category><category>Criptografia</category></item><item><title>Data lake vs data warehouse — e onde entra o lakehouse</title><link>https://cesarschutz.com.br/posts/data-lake-vs-data-warehouse/</link><guid isPermaLink="true">https://cesarschutz.com.br/posts/data-lake-vs-data-warehouse/</guid><description>Schema-on-write vs schema-on-read, ETL vs ELT, dado curado vs dado bruto: o comparativo direto entre Data Warehouse e Data Lake, por que os dois costumam trabalhar juntos e o que o Lakehouse propõe unificar.</description><pubDate>Tue, 31 Mar 2026 00:00:00 GMT</pubDate><category>Dados</category><category>Trade-offs</category><category>AWS</category></item><item><title>Guia de atualizações do Java</title><link>https://cesarschutz.com.br/posts/guia-atualizacoes-java/</link><guid isPermaLink="true">https://cesarschutz.com.br/posts/guia-atualizacoes-java/</guid><description>Como planejar a migração entre LTS do Java: ciclo de releases, distribuições e licenças, versões mínimas do ecossistema, processo em cinco fases com rollback, segurança, desempenho, containers e CI.</description><pubDate>Mon, 14 Jul 2025 00:00:00 GMT</pubDate><category>Atualizações do Java</category><category>LTS</category><category>Migração</category><category>JVM</category><category>Gradle</category></item><item><title>Java 25 (LTS) — arquivos-fonte compactos, Scoped Values, cache AOT e criptografia pós-quântica</title><link>https://cesarschutz.com.br/posts/java-25/</link><guid isPermaLink="true">https://cesarschutz.com.br/posts/java-25/</guid><description>Do Java 22 ao 25, para quem vem do Java 21: arquivos compactos, import module, construtores flexíveis, Scoped Values, cache AOT, headers compactos, criptografia pós-quântica e as 66 JEPs.</description><pubDate>Wed, 02 Jul 2025 02:50:00 GMT</pubDate><category>Atualizações do Java</category><category>LTS</category><category>Linguagem</category><category>JVM</category><category>Criptografia</category></item><item><title>Java 21 (LTS) — virtual threads, pattern matching e Sequenced Collections</title><link>https://cesarschutz.com.br/posts/java-21/</link><guid isPermaLink="true">https://cesarschutz.com.br/posts/java-21/</guid><description>O que mudou do Java 17 ao Java 21: virtual threads, pattern matching para switch, record patterns, Sequenced Collections, ZGC geracional e as 38 JEPs do Java 18 ao 21, com a versão em que cada recurso chegou.</description><pubDate>Wed, 02 Jul 2025 02:10:00 GMT</pubDate><category>Atualizações do Java</category><category>LTS</category><category>Linguagem</category><category>Virtual Threads</category><category>Concorrência</category></item><item><title>Java 17 (LTS) — records, sealed classes, text blocks e switch expressions</title><link>https://cesarschutz.com.br/posts/java-17/</link><guid isPermaLink="true">https://cesarschutz.com.br/posts/java-17/</guid><description>Do Java 12 ao 17, versão a versão: records, sealed classes, text blocks, switch expressions, pattern matching para instanceof, ZGC e Shenandoah em produção e o que quebra vindo do Java 11.</description><pubDate>Wed, 02 Jul 2025 01:30:00 GMT</pubDate><category>Atualizações do Java</category><category>LTS</category><category>Linguagem</category><category>JVM</category><category>Migração</category></item><item><title>Java 11 (LTS) — módulos, var, HTTP Client e o novo ciclo de releases</title><link>https://cesarschutz.com.br/posts/java-11/</link><guid isPermaLink="true">https://cesarschutz.com.br/posts/java-11/</guid><description>O que chegou do Java 9 ao 11 para quem migra do Java 8: sistema de módulos, var, HttpClient, novas APIs, G1 como padrão, TLS 1.3, a remoção do Java EE e do CORBA e o ciclo de releases a cada seis meses.</description><pubDate>Wed, 02 Jul 2025 00:30:00 GMT</pubDate><category>Atualizações do Java</category><category>LTS</category><category>Linguagem</category><category>JVM</category><category>Migração</category></item><item><title>Java 8 (LTS) — lambdas, Stream API, java.time e o fim do PermGen</title><link>https://cesarschutz.com.br/posts/java-8/</link><guid isPermaLink="true">https://cesarschutz.com.br/posts/java-8/</guid><description>O que mudou do Java 7 para o Java 8: lambdas, Stream, Optional, java.time, CompletableFuture e Metaspace no lugar do PermGen, com exemplos antes e depois e a lista completa das 55 JEPs.</description><pubDate>Wed, 02 Jul 2025 00:00:00 GMT</pubDate><category>Atualizações do Java</category><category>LTS</category><category>Linguagem</category><category>JVM</category><category>Concorrência</category></item></channel></rss>