Ambiente de execução do Java 7

Aviso: o ambiente de execução do Java 7 teve seu uso suspenso. As implantações de apps nesse ambiente estão bloqueadas, e o SDK para Java versão 1.9.72 ou mais recentes não permitem a criação de aplicativos em Java 7.

Se seu aplicativo estiver usando o ambiente de execução do Java 7, ele será automaticamente migrado para o ambiente de execução do Java 8. O Google continuará a oferecer suporte para o ambiente de execução do Java 7 de acordo com os Termos de Serviço. Migre para o ambiente de execução do Java 8 o mais rápido possível.

Com o App Engine, é possível criar aplicativos da Web para usar a infraestrutura e os serviços escalonáveis do Google.

Introdução

No App Engine, seu aplicativo Java da Web é executado em uma JVM Java 8 (em inglês), em um ambiente seguro colocado em sandbox. As classes de servlet do aplicativo são invocadas para lidar com solicitações e preparar respostas nesse ambiente.

No ambiente de execução do Java 7 para App Engine, que é baseado no OpenJDK 7, o padrão Java Servlet 2.5 é usado para aplicativos da Web. Informe as classes de servlet do aplicativo, as páginas do JavaServer (JSPs, na sigla em inglês), os arquivos estáticos e de dados, junto com o descritor de implantação (o arquivo web.xml) e outros arquivos de configuração em uma estrutura de diretórios WAR padrão. Para a veiculação das solicitações, os servlets são invocados de acordo com o descritor de implantação.

O ambiente seguro em "sandbox" isola o aplicativo para melhorar o serviço e a segurança. Ele garante que os apps só possam executar ações que não interfiram no desempenho e na escalonabilidade de outros apps. Por exemplo, não é possível para o aplicativo gerar threads de algumas formas, gravar dados no sistema de arquivos local ou fazer conexões de rede arbitrárias. Um aplicativo também não pode usar JNI ou outros códigos nativos. Na JVM, é possível executar qualquer bytecode Java que opere dentro das restrições do sandbox.

Na plataforma do App Engine, são oferecidos muitos serviços que o código pode chamar. O aplicativo também pode configurar tarefas programadas executadas em intervalos especificados.

No tutorial do aplicativo Guestbook Java, está descrita uma introdução ao desenvolvimento de aplicativos da Web com tecnologias Java e App Engine.

Como selecionar o ambiente de execução do Java 8

A API App Engine para Java é representada pelo appengine-api-*.jar incluído no SDK do App Engine como parte do SDK do Cloud, em que * representa a versão da API e do SDK do App Engine.

Selecione a versão da API usada pelo aplicativo ao incluir esse JAR no diretório WEB-INF/lib/ do app ou então use o Maven para processar dependências. Se uma nova versão do Java Runtime Environment for lançada e apresentar mudanças incompatíveis com os aplicativos existentes, esse ambiente terá um novo número de versão. O aplicativo continuará a usar a versão anterior até que você substitua o JAR pela nova versão de um SDK do App Engine mais recente e faça o novo upload do aplicativo.

Como usar o Maven para lidar com dependências

Você pode usar o Maven para gerenciar todas as dependências. Por exemplo, a entrada pom.xml inclui a mais recente API App Engine (Rappengine-api-1.0-sdk) disponível na central do Maven:

<dependency>
    <groupId>com.google.appengine</groupId>
    <artifactId>appengine-api-1.0-sdk</artifactId>
    <version><span class="notranslate exporttrans-dynamic">print setvar.appengine_java_version</span></version>
</dependency>

O sandbox

Para permitir que o App Engine distribua solicitações para aplicativos em vários servidores da Web e evitar que um aplicativo interfira no outro, o aplicativo é executado em um ambiente em sandbox restrito. Nesse ambiente, o aplicativo pode executar código, armazenar e consultar dados no Cloud Datastore, usar os serviços de e-mail, busca de URL e usuários do App Engine, além de examinar a solicitação da Web do usuário e preparar a resposta.

Um aplicativo do App Engine não pode:

  • gravar no sistema de arquivos. Os aplicativos precisam usar o Cloud Datastore para armazenar dados persistentes. É permitido ler o sistema de arquivos, e todos os arquivos enviados com o aplicativo estão disponíveis;

  • demorar para responder. Uma solicitação da Web para um aplicativo precisa ser processada em poucos segundos. Os processos que levam muito tempo para responder são encerrados para evitar sobrecarregar o servidor da Web;

  • fazer outros tipos de chamadas do sistema.

Sistema de arquivos

O aplicativo em Java não pode usar as classes utilizadas para gravação no sistema de arquivos como java.io.FileWriter. O aplicativo tem permissão para a leitura dos próprios arquivos do sistema com o uso de classes como java.io.FileReader. O aplicativo também tem acesso aos próprios arquivos como "recursos", como com Class.getResource() ou ServletContext.getResource().

Somente arquivos considerados "arquivos de recursos" estão acessíveis para o aplicativo por meio do sistema de arquivos. Por padrão, todos os arquivos no "WAR" são do tipo recursos. Para excluir arquivos desse conjunto, use o appengine-web.xml.

java.lang.System

Os recursos da classe java.lang.System que não se aplicam ao App Engine são desativados.

Os seguintes métodos do System não têm efeito no App Engine: exit(), gc(), runFinalization() e runFinalizersOnExit()

O retorno é null para os seguintes métodos do System: inheritedChannel(), console()

Um aplicativo não pode fornecer ou invocar diretamente qualquer código JNI nativo. Os seguintes métodos do System geram java.lang.SecurityException: load(), loadLibrary() e setSecurityManager()

Reflexão

O aplicativo tem acesso total, irrestrito e refletivo às próprias classes.

Com ele, é possível consultar qualquer membro privado, chamar o método java.lang.reflect.AccessibleObject.setAccessible() e ler ou configurar membros privados.

Com um aplicativo, também é possível refletir em classes JRE e API como java.lang.String e javax.servlet.http.HttpServletRequest. No entanto, ele acessa somente os membros públicos (que não estejam protegidos ou sejam privados) dessas classes.

Com um aplicativo, não é possível refletir nenhuma outra classe que não pertença a ele nem usar o método setAccessible() para contornar essas restrições.

Como carregar classes personalizadas

O carregamento de classes personalizadas é totalmente compatível com o App Engine. É possível definir uma subclasse de ClassLoader própria para o aplicativo que implemente uma lógica de carregamento de classe específica. No entanto, todos os ClassLoaders são substituídos pelo App Engine para a atribuição das mesmas permissões a todas as classes carregadas pelo aplicativo. Se você executar o carregamento de classes personalizadas, tenha cuidado ao carregar códigos não confiáveis de terceiros.

Como fazer a ordenação de JAR do carregador de classe

Às vezes, pode ser necessário redefinir a ordem em que as classes são verificadas nos arquivos JAR para resolver conflitos entre os nomes das classes. Nesses casos, a prioridade de carregamento pode ser concedida a arquivos JAR específicos adicionando um elemento <class-loader-config> que contém elementos <priority-specifier> no arquivo appengine-web.xml. Exemplo:

<class-loader-config>
  <priority-specifier filename="mailapi.jar"/>
</class-loader-config>

Isso coloca "mailapi.jar" como o primeiro arquivo JAR em que as classes serão pesquisadas, excluindo os arquivos no diretório war/WEB-INF/classes/.

Se vários arquivos JAR forem priorizados, a ordem de carregamento original deles (em relação um ao outro) será usada. Em outras palavras, a ordem dos próprios elementos <priority-specifier> não importa.

Lista de permissões do JRE

O acesso às classes da biblioteca padrão do Java (o Java Runtime Environment ou JRE) é limitado às classes na lista de permissões do JRE no App Engine.

Nenhum arquivo JAR assinado

A pré-compilação do App Engine não é compatível com arquivos JAR assinados. Se o aplicativo for pré-compilado (o padrão), não será possível carregar arquivos JAR assinados. Se houver a tentativa de carregar um JAR assinado, uma exceção como a que está abaixo será gerada no ambiente de execução:

java.lang.SecurityException: SHA1 digest error for com/example/SomeClass.class
    at com.google.appengine.runtime.Request.process-d36f818a24b8cf1d(Request.java)
    at sun.security.util.ManifestEntryVerifier.verify(ManifestEntryVerifier.java:210)
    at java.util.jar.JarVerifier.processEntry(JarVerifier.java:218)
    at java.util.jar.JarVerifier.update(JarVerifier.java:205)
    at java.util.jar.JarVerifier$VerifierStream.read(JarVerifier.java:428)
    at sun.misc.Resource.getBytes(Resource.java:124)
    at java.net.URLClassLoader.defineClass(URLClassLoader.java:273)
    at sun.reflect.GeneratedMethodAccessor5.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:616)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:266)

Há duas maneiras de lidar com isso:

Threads

Um thread pode ser criado pelo aplicativo Java, mas a maneira de fazer isso tem algumas restrições. Esses threads não podem "viver mais" do que a solicitação que os cria.

Com um aplicativo, é possível

No entanto, é preciso usar um dos métodos do ThreadManager para criar os threads. Não é possível chamar new Thread() você mesmo ou usar a fábrica de linhas de execução padrão (em inglês).

Com um aplicativo, é possível executar operações em relação ao thread atual, como thread.interrupt().

Cada solicitação é limitada a 50 threads de solicitação simultâneos. O ambiente de execução do Java gerará java.lang.IllegalStateException se você tentar criar mais de 50 threads em uma solicitação.

Quando usar threads, utilize objetos de simultaneidade de alto nível, como Executor e Runnable. Eles cuidam de detalhes sutis, mas importantes, da simultaneidade como interrupções e agendamento e contabilidade (conteúdo dos links em inglês).

Threads em segundo plano

O código em execução nas instâncias de escalonamento manual ou básico pode iniciar um thread em segundo plano capaz de sobreviver à solicitação que o gera. Com isso, as instâncias podem ser usadas para executar tarefas periódicas ou programadas arbitrárias ou podem continuar funcionando em segundo plano, depois que uma solicitação for retornada ao usuário.

A simultaneidade Java pode causar problemas difíceis de depurar. Para evitar o uso de threads, utilize filas de tarefas, tarefas programadas ou o Pub/Sub.

As entradas de registro de um thread em segundo plano são independentes das entradas do thread de geração. Leia mais sobre threads de segundo plano na documentação do ThreadManager do App Engine.

import com.google.appengine.api.ThreadManager;
import java.util.concurrent.atomic.AtomicLong;

AtomicLong counter = new AtomicLong();

Thread thread = ThreadManager.createBackgroundThread(new Runnable() {
  public void run() {
    try {
      while (true) {
        counter.incrementAndGet();
        Thread.sleep(10);
      }
    } catch (InterruptedException ex) {
      throw new RuntimeException("Interrupted in loop:", ex);
    }
  }
});
thread.start();

Se o código em execução em um serviço de escalonamento automático tentar iniciar um thread em segundo plano, uma exceção será gerada.

O número máximo de threads simultâneos em segundo plano criados pela API App Engine é de 10 por instância. Esse limite não se aplica a segmentos comuns do Java não relacionados à API App Engine.

Ferramentas

IDEs compatíveis

Com o Cloud Tools for Eclipse, novos assistentes de projeto e configurações de depuração são adicionados ao ambiente de desenvolvimento integrado do Eclipse (em inglês) em projetos do App Engine. Você pode implantar seus projetos do App Engine dinamicamente na produção de dentro do Eclipse.

Com o Cloud Tools for IntelliJ, é possível executar e depurar aplicativos do App Engine no IntelliJ IDEA (em inglês). Os projetos do App Engine podem ser implantados dinamicamente no ambiente de produção sem sair do ambiente de desenvolvimento integrado.

Ferramentas de compilação compatíveis

Para acelerar o processo de desenvolvimento, use os plug-ins do App Engine para Apache Maven ou Gradle:

Servidor de desenvolvimento local

O servidor de desenvolvimento executa seu aplicativo no computador local de desenvolvimento e testes. O servidor simula os serviços do Cloud Datastore. O servidor de desenvolvimento também pode gerar configuração para índices do Cloud Datastore com base nas consultas que o aplicativo executa durante os testes.

AppCfg

O AppCfg está incluído no SDK independente do App Engine para Java. Ele é uma ferramenta multifuncional que lida com a interação da linha de comando com seu aplicativo em execução no App Engine. O AppCfg pode fazer o upload do seu aplicativo no App Engine ou simplesmente atualizar a configuração do índice do Cloud Datastore para que você possa criar novos índices antes de atualizar o código. Ele também faz o download dos dados de registro do app para possibilitar a análise do desempenho do aplicativo usando as próprias ferramentas.

Simultaneidade e latência

A latência do seu aplicativo tem o maior impacto no número de instâncias necessárias para disponibilizar o tráfego. Se você processa solicitações rapidamente, uma única instância pode lidar com muitas solicitações.

As instâncias de thread único podem processar uma solicitação simultânea. Portanto, há uma relação direta entre a latência e número de solicitações que podem ser processadas na instância por segundo. Por exemplo, a latência de 10 ms é igual a 100 pedidos/segundo/instância.

As instâncias com vários threads podem processar várias solicitações simultâneas. Portanto, há uma relação direta entre a CPU consumida e o número de solicitações/segundo.

Os aplicativos Java são compatíveis com solicitações simultâneas, portanto, uma única instância pode processar novas solicitações enquanto aguarda que outras sejam concluídas. A simultaneidade reduz significativamente o número de instâncias que seu aplicativo requer, mas você precisa projetar seu aplicativo para vários threads.

Por exemplo, se uma instância B4 (aproximadamente 2,4 GHz) consome 10 milhões de ciclos/solicitação, você pode processar 240 solicitações/segundo/instância. Se ela consome 100 milhões de ciclos/solicitação, você pode processar 24 solicitações/segundo/instância. Esses números são o caso ideal, mas são bem realistas em termos do que é possível realizar em uma instância.

Esta página foi útil? Conte sua opinião sobre:

Enviar comentários sobre…

Ambiente padrão do App Engine para Java 8