Los métodos y las clases básicas

(Enero de 2005)

Clases y métodos

Todo servlet hereda de HttpServlet y, al igual que un applet, contiene una serie de métodos predefinidos, que son invocados en respuesta a eventos:

La primera vez que invocamos al servlet se crea una instancia de la clase en un hilo (thread) de ejecución, se llama a init() e inmediatamente después al método doXX() correspondiente. Las siguientes peticiones generan un hilo independiente, pero no una nueva instancia. Veamos un ejemplo, supongamos que un servlet tiene el atributo:


    private int contador = 0;
    

y al principio del método doXX() se incrementa:


	contador++;
    

La primera invocación al servlet implica que se crea la instancia y el valor del atributo será uno. En la siguiente invocación (en su hilo independiente) no se genera una instancia, por lo que el valor del atributo se vuelve a incrementar y así sucesivamente. Pruebe a hacerlo y visualizar el valor de la variable. Verá que todas las peticiones (invocaciones) al servlet comparten los mismos datos (las variables atributo). El lector se puede plantear que hay situaciones en las que nos interesa que la sesión mantenga datos propios, no compartidos con otras sesiones. Por ejemplo, cuando estamos en una web transaccional (una tienda electrónica) queremos que cada sesión pueda utilizar datos específicos, como la identificación de usuario o el carrito de la compra. Esto se puede hacer (además de usando una base de datos) manejando información específica a la sesión, pero esto es asunto de estudio posterior.

init()

Invoca al servlet de ejemplo.

También tienes acceso al código fuente.

Veamos que se puede hacer con init():

  1. Obtenemos el nombre del servlet por medio de una llamada al método getServletName() del parámetro config.
  2. 
           m.append("Servlet '"+config.getServletName()+"' arrancado a las " + new Date() );
        


  3. Obtenemos los parámetros de ServletConfig. Para lo cual nos hacemos con una Enumeration que nos permite recorrer todos los nombre de parámetros, obteniendo su valor por medio de getInitParameter( nombre_parametro ). No confundir estos parámetros con los de la petición (request). Ahora nos centramos en los parámetros de inicio, que se obtienen de web.xml. Los otros se obtienen de la petición (normalmente de un formulario HTML). El ejemplo de código para obtenerlos está a continuación; se puede observar que introducimos el contenido en un StringBuffer (atributo m). La razón de ello es que debemos almacenar el contenido en el inicio del servlet para que puedan acceder a él múltiples peticiones posteriores:
  4. 
           m.append( "<OL>");
           for ( Enumeration e= config.getInitParameterNames(); e.hasMoreElements(); ) {
    	   String nom_par = (String) e.nextElement();                    // Obtiene nombre del parámetro
    	   m.append("<LI>Parámetro de ServletConfig: " + nom_par);
    	   m.append(". Valor: " + config.getInitParameter( nom_par ) );  // Obtiene valor del parametro
           }
           m.append( "</OL>");
    	

    En nuestro caso, posteriormente (doPost()/doGet()), obtendremos en la visualización lo siguiente:

    
    	   1. Parámetro de ServletConfig: CURSO. Valor: SERVLETS
    	

    La razón es que hemos puesto en web.xml los siguientes parámetros de inicio:

    
      <servlet>
        <servlet-name>Metodos</servlet-name>
        <servlet-class>docen_servlet01.Metodos</servlet-class>
    		<init-param>
    			<param-name>CURSO</param-name>
    			<param-value>SERVLETS</param-value>
    		</init-param>
      </servlet>
    	


  5. Después obtenemos el contexto del servlet, también a partir de config:
    
    	ServletContext sc = config.getServletContext();
    	
    La información que se requiere a partir de aquí es servida por el objeto sc de la clase ServletContext. De los siguientes atributos de contexto el más interesante tal vez sea getRealPath("/"), que nos devuelve el directorio raíz del contexto de aplicación:
  6. 
           m.append( "<P>RealPath: " + sc.getRealPath( "/") );
           m.append( "<P>ServerInfo: " + sc.getServerInfo() );// Nombre del servidor web
           m.append( "<P>Versión API Servlet: " + sc.getMajorVersion() + "." +sc.getMinorVersion() ); //API
    	
    Observar la diferencia en J2EE entre servlet y aplicacióin. Nuestro servlet está en ROOT\WEB-INF\classes, dentro de la aplicación ROOT. La aplicación engloba a una serie de servlets entre los que está el nuestro. La diferencia entre servlet y aplicación es la que existe entre un contenido y un contenedor.

  7. Una enumeración de atributos del servidor:
  8. 
           m.append( "<OL>");
           for ( Enumeration e= sc.getAttributeNames(); e.hasMoreElements(); ) {
    	   String nom_par = (String) e.nextElement(); // Obtenemos el nombre del atrib
    	   m.append("<LI>Atributo de contexto: " + nom_par);
    	   m.append(". Valor: " + sc.getAttribute( nom_par ) ); // Se obtiene el valor del atrib
           }
           m.append( "</OL>");
    	


  9. Por último, utilizamos el contexto del servlet para escribir un texto de aviso en el archivo log del servidor de aplicaciones (o en la consola, dependiendo de la configuración). La ubicación y nombre del archivo depende de la instalación y configuración de cada servidor.
  10. 
           sc.log( "----> Inicio de servlet Metodos" ); // Salida a archivo LOG del serv de apps
    	

En el código fuente se puede observar que toda esta información se vuelca en StringBuffer m. La finalidad de almacenarla es que luego (en el método doGet) podremos obtenerla para imprimir los datos.

doGet()/doPost(), mostrando además los atributos del sistema

Nuestro método doGet() reenvia la petición a doPost():


   public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
      doPost(request, response);
   }
	

En doPost() la forma de presentar la información de inicio que ha sido almacenada en el StringBuffer es muy sencilla:


       out.println( m );
	

A continuación mostramos los atributos del sistema (System). Lo primero es obtener todas las propiedades por medio de System.getProperties(). En segundo lugar obtenemos una Enumeration de las claves (nombres de propiedades):


       Properties p = System.getProperties();
       Enumeration enum= p.keys();
	

Obtener los valores es tan sencillo como llamar a getProperty() para cada clave:


       for (Enumeration enum= p.keys(); enum.hasMoreElements(); ) {
	  String clave = (String) enum.nextElement();
	  out.println( "<TR><TD>CLAVE: " + clave + "</TD>" );
	  out.println( "<TD>" + p.getProperty(clave) + "</TD></TR>" );
       }
	

Destrucción del servlet

La función destroy() del servlet se ejecuta cuando éste va a ser destruido (normalmente por la detención del servidor). No se invoca cuando se termina la petición, sino cuando se va a descargar el servlet de memoria.

El programador debe liberar o cerrar recursos, como conexiones o flujos de entrada/salida. Ante esto, surge un interrogante, en peticiones de larga resolución pudiera ocurrir que se liberen recursos que todavía son necesarios. Supongamos que hay un usuario que esta comprando o transfiriendo dinero y en estos momento la petición está en doPost(), si produjesemos una desconexión el usuario se quedaría a medias. Para evitar esto el servidor tiene dos estrategias: no ejecuta destroy() hasta que han terminado las llamadas a las funciones de respuesta (doGet, doPost y service) o, en segundo lugar, hasta que termine un "periodo de gracia".

Para más información: Tutorial de Sun


Volver al índice