Mis favoritos | Español | Acceder

El entorno Java Servlet

App Engine ejecuta tu aplicación web Java a través de JVM Java 6 en un entorno seguro de la "zona de pruebas". App Engine ejecuta las clases de servlet de tu aplicación para procesar solicitudes y preparar respuestas en este entorno.

Selección de la versión del API Java

App Engine sabe utilizar el entorno de tiempo de ejecución Java para tu aplicación cuando utilizas la herramienta AppCfg del kit de desarrollo de software (SDK) de Java para subir la aplicación.

Al igual que ocurre con este artículo, sólo existe una versión del API Java de App Engine. Esta API se representa mediante el JAR appengine-api-*.jar incluido en el SDK (en el que * representa la versión del API y del SDK). Selecciona la versión del API que tu aplicación utiliza incluyendo este JAR en el directorio WEB-INF/lib/ de la aplicación. Si se publica una nueva versión del entorno de tiempo de ejecución Java que introduzca cambios no compatibles con las aplicaciones existentes, ese entorno dispondrá de un nuevo número de versión. Tu aplicación seguirá utilizando la versión anterior hasta que sustituyas el JAR por la nueva versión (de un SDK más nuevo) y vuelvas a subir la aplicación.

Solicitudes y servlets

Cuando App Engine recibe una solicitud web para tu aplicación, ejecuta el servlet correspondiente de la URL, como se describe en el descriptor de implementación (el archivo web.xml del directorio WEB-INF/). Utiliza el API Java Servlet para proporcionar los datos de la solicitud al servlet y acepta los datos de respuesta.

App Engine utiliza varios servidores web para ejecutar tu aplicación y ajustará automáticamente el número de servidores en uso para procesar las solicitudes de una forma segura. Una determinada solicitud se puede enviar a cualquier servidor, que no tiene que ser el mismo servidor que procesó una solicitud anterior procedente del mismo usuario.

En la siguiente clase de servlet de ejemplo aparece un mensaje sencillo en el navegador del usuario.

import java.io.IOException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class MyServlet extends HttpServlet {
    public void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws IOException {
        resp.setContentType("text/plain");
        resp.getWriter().println("Hello, world");
    }
}

Respuestas

App Engine ejecuta el servlet con un objeto de solicitud y un objeto de respuesta y, a continuación, espera a que el servlet rellene el objeto de respuesta y vuelva. Cuando el servidor vuelve, los datos del objeto de respuesta se envían al usuario.

App Engine no admite el envío de datos al cliente, la realización de más cálculos en la aplicación y el posterior envío de más datos. En otras palabras, App Engine no admite la "transmisión" de datos como respuesta a una única solicitud.

Si el cliente envía encabezados HTTP en la solicitud que indiquen que el cliente puede aceptar contenido comprimido (gzip), App Engine comprimirá automáticamente los datos de respuesta y adjuntará los encabezados de respuesta correspondientes. Utiliza tanto los encabezados de solicitud Accept-Encoding como User-Agent para determinar si el cliente puede recibir respuestas comprimidas de forma segura. Los clientes personalizados fuerzan la compresión del contenido mediante la especificación de los encabezados Accept-Encoding y User-Agent con un valor "gzip".

Período de tiempo de solicitudes

Un controlador de solicitudes dispone de una cantidad de tiempo limitada para generar y devolver una respuesta a una solicitud, en general, 30 segundos aproximadamente. Una vez alcanzado el plazo, el controlador de solicitudes se interrumpe.

El entorno de tiempo de ejecución Java interrumpe el servlet y genera una excepción com.google.apphosting.api.DeadlineExceededException. Si el controlador de solicitud no detecta esta ni otras excepciones, el entorno de tiempo de ejecución devuelve al cliente un error de servidor HTTP 500.

El controlador de solicitud puede detectar este error para personalizar la respuesta. El entorno de tiempo de ejecución proporciona al controlador de solicitud un poco de más tiempo (menos de un segundo) tras establecer la excepción para preparar una respuesta personalizada.

Mientras que la respuesta a una solicitud puede tardar hasta 30 segundos, App Engine se optimiza para aplicaciones con solicitudes breves, normalmente aquellas que tardan unos cien milisegundos. Una aplicación eficaz responde rápidamente a la mayoría de las solicitudes. Una aplicación que no lo hace, no se ampliará correctamente con la infraestructura de App Engine.

La zona de pruebas

Para permitir a App Engine distribuir solicitudes para aplicaciones a través de varios servidores web y evitar que una aplicación interfiera en otra, la aplicación se ejecuta en un entorno de "zona de pruebas" restringido. En este entorno, la aplicación puede ejecutar datos de consulta, almacenamiento y código en el almacén de datos de App Engine, utilizar el correo de App Engine, la extracción de URL y los servicios de usuarios, y examinar las solicitudes web del usuario y preparar la respuesta.

Una aplicación App Engine no puede:

  • escribir en el sistema de archivos. Las aplicaciones deben utilizar el almacén de datos de App Engine para almacenar los datos persistentes. La lectura desde el sistema de archivos está permitida y todos los archivos de aplicación subidos con la aplicación están disponibles.
  • abrir un socket ni acceder a otro host directamente. Una aplicación puede utilizar el servicio de extracción de URL de App Engine para realizar solicitudes HTTP y HTTPS a otros hosts en los puertos 80 y 443, respectivamente.
  • generar un subproceso. El procesamiento de una solicitud web a una aplicación debe ser un único proceso que dure unos cuantos segundos. Los procesos que tardan mucho tiempo en responder se finalizan para evitar la sobrecarga del servidor web.
  • realizar otro tipo de llamadas al sistema.

Cadenas

Una aplicación Java no puede crear un nuevo grupo de cadenas java.lang.ThreadGroup ni una nueva cadena java.lang.Thread. Estas restricciones también se aplican a las clases JRE que utilizan cadenas. Por ejemplo, una aplicación no puede crear un nuevo java.util.concurrent.ThreadPoolExecutor o un temporizador java.util.Timer. Una aplicación puede realizar operaciones relacionadas con la cadena actual como, por ejemplo, Thread.currentThread().dumpStack().

El sistema de archivos

Una aplicación Java no puede utilizar ninguna clase que se utilice para escribir en el sistema de archivos como, por ejemplo, java.io.FileWriter. Una aplicación puede leer sus propios archivos del sistema de archivos a través de clases como, por ejemplo, java.io.FileReader. Una aplicación también puede acceder a sus propios archivos como "recursos", como en el caso de Class.getResource() o ServletContext.getResource().

La aplicación sólo puede acceder a los archivos que se consideran "archivos de recursos" a través del sistema de archivos. De forma predeterminada, todos los archivos del WAR son "archivos de recursos". Puedes excluir archivos de este conjunto a través del archivo appengine-web.xml.

java.lang.System

Se han inhabilitado las funciones de la clase java.lang.System que no se aplican a App Engine.

Los siguientes métodos System no hacen nada en App Engine: exit(), gc(), runFinalization() y runFinalizersOnExit().

Los siguientes métodos System devuelven null: inheritedChannel() y console().

Una aplicación no puede proporcionar ni ejecutar de forma directa ningún código JNI original. Los siguientes métodos System establecen una excepción java.lang.SecurityException: load(), loadLibrary() y setSecurityManager().

Reflejo

Una aplicación tiene acceso reflectante, ilimitado y completo a sus propias clases. Puede realizar la consulta de cualquier miembro privado, utilizar java.lang.reflect.AccessibleObject.setAccessible() y leer/establecer miembros privados.

Una aplicación también puede reflejarse en las clases JRE y API como, por ejemplo, java.lang.String y javax.servlet.http.HttpServletRequest. Sin embargo, sólo puede acceder a miembros públicos de estas clases, no protegidos o privados.

Una aplicación no pueden reflejarse en ninguna otra clase que no pertenezca a sí misma y no puede utilizar el método setAccessible() para evitar estas restricciones.

Carga de clases personalizadas

App Engine admite completamente la carga de clases personalizadas. Sin embargo, debes tener en cuenta que App Engine anula todos los ClassLoaders para asignar los mismos permisos a todas las clases cargadas por aplicación. Si realizas una carga de clases personalizadas, ten cuidado al cargar código de terceros que no sean de confianza.

Accesos permitidos a la clase de JRE

El acceso a las clases de la biblioteca estándar de Java (el entorno de tiempo de ejecución Java o JRE) se limita a las clases de los accesos a JRE de App Engine.

Registro

Tu aplicación puede escribir información en los registros a través de java.util.logging.Logger. Puedes ver y analizar los datos de registro de tu aplicación con la consola de administración o descargarlos mediante appcfg.sh request_logs. La consola de administración puede reconocer los Loggerniveles de registro de la clase y mostrar mensajes de forma interactiva a diferentes niveles.

App Engine detecta y registra en los registros de la aplicación todo lo que el servlet escriba en el flujo de salida estándar (System.out) y en el flujo de error estándar (System.err). Las líneas que se escriben en el flujo de salida estándar se registran en el nivel "INFO" y las que se escriben en el flujo de error estándar se registran en el nivel "ADVERTENCIA". Puede funcionar cualquier framework de registro (como, por ejemplo, log4j) que se registre en los flujos de error o de salida. Sin embargo, para un control más preciso de la visualización del nivel de registro de la consola de administración, el framework de registro debe utilizar un adaptador java.util.logging.

import java.util.logging.Logger;
// ...

public class MyServlet extends HttpServlet {
    private static final Logger log = Logger.getLogger(MyServlet.class.getName());

    public void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws IOException {

        log.info("An informational message.");

        log.warning("A warning message.");

        log.severe("An error message.");
    }
}

El SDK de Java de App Engine incluye un archivo logging.properties de plantilla en el directorio appengine-java-sdk/config/user/. Para utilizarlo, copia el archivo en tu directorio WEB-INF/classes (o en cualquier otro directorio del WAR) y, a continuación, la propiedad del sistema java.util.logging.config.file en "WEB-INF/classes/logging.properties" (o cualquier otra ruta que elijas y que esté relacionada con el directorio raíz de la aplicación). Puedes establecer las propiedades del appengine-web.xmlarchivo, como se muestra a continuación:

<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
    ...

    <system-properties>
        <property name="java.util.logging.config.file" value="WEB-INF/classes/logging.properties" />
    </system-properties>

</appengine-web-app>

El nuevo asistente de proyectos del complemento de Google para Eclipse crea estos archivos de configuración de registro y los copia en WEB-INF/classes/ de forma automática. Para java.util.logging, debes establecer la propiedad del sistema que utilice este archivo.

El entorno

Todas las propiedades del sistema y variables de entorno son privadas para tu aplicación. El establecimiento de una propiedad del sistema sólo afecta a la vista de esa propiedad de tu aplicación, no a la vista de JVM.

Puedes establecer propiedades del sistema y variables de entorno para tu aplicación en el descriptor de implementación.

App Engine establece las siguientes propiedades del sistema cuando inicializa JVM en un servidor de aplicaciones:

  • file.separator
  • path.separator
  • line.separator
  • java.version
  • java.vendor
  • java.vendor.url
  • java.class.version
  • java.specification.version
  • java.specification.vendor
  • java.specification.name
  • java.vm.vendor
  • java.vm.name
  • java.vm.specification.version
  • java.vm.specification.vendor
  • java.vm.specification.name
  • user.dir

Cuotas y límites

Todas las solicitudes de entrada de la aplicación se contabilizan en la cuota de Solicitudes.

Los datos recibidos como parte de una solicitud se contabilizan en la cuota de ancho de banda de entrada (facturable). Los datos enviados como respuesta a una solicitud se contabilizan en la cuota de ancho de banda de salida (facturable).

Tanto las solicitudes HTTP como HTTPS (seguras) se contabilizan en las cuota de solicitudes, en la de ancho de banda de entrada (facturable) y en la de ancho de banda de salida (facturable). La página de detalles de cuota de la consola de administración también informa sobre solicitudes seguras, ancho de banda de entrada seguro y ancho de banda de salida seguro como valores independientes únicamente con finalidad informativa. Sólo las solicitudes HTTPS se contabilizan en estos valores.

El tiempo de procesamiento de CPU empleado en ejecutar un controlador de solicitudes se contabiliza en la cuota de Tiempo de CPU (facturable).

Para obtener más información sobre cuotas, consulta la sección Cuotas y la sección "Detalles de cuota" de la consola de administración.

Además de las cuotas, al controlador de solicitudes se le aplican los siguientes límites:

Límite Valor
tamaño de la solicitud 10 megabytes
tamaño de la respuesta 10 megabytes
duración de la solicitud 30 segundos
solicitudes dinámicas simultáneas 30 *
número máximo de archivos de aplicación 1.000
número máximo de archivos estáticos 1.000
tamaño máximo de un archivo de aplicación 10 megabytes
tamaño máximo de un archivo estático 10 megabytes
tamaño total máximo de todos los archivos estáticos y de aplicación 150 megabytes

* Una aplicación puede procesar alrededor de 30 solicitudes dinámicas activas simultáneamente. Esto significa que, una aplicación cuya media de tiempo de procesamiento de solicitudes del servidor sea de 75 milisegundos podrá presentar hasta (1.000 ms/segundo / 75 ms/solicitud) * 30 = 400 solicitudes/segundo sin conllevar latencia adicional. Las aplicaciones que tienen un límite de CPU considerable pueden conllevar latencia adicional en solicitudes prolongadas a fin de crear espacio para otras aplicaciones que compartan los mismos servidores. Las solicitudes para archivos estáticos no se ven influidas por este límite.