Programação Na Web Servlets: Ciclo de Vida António Gonçalves 1 Agenda Visão geral sobre ciclo de vida Nascimento de uma Servlet Execução de uma Servlet Destruição de uma Servlet 2 Servlet Life Cycle http://ltodi.est.ips.pt/leonardo/ci/M aterialA poio.htm 1 Ciclo de Vida de uma Servlet • init – È executado só uma vez quando a servlet é carregada. Não é chamado em pedidos subsequentes • service – Chamado num novo thread pelo servidor para cada pedido. Faz a chamada dos métodos doGet, doPost, etc. Este método não deve ser sobreposto ! • doGet, doPost, doXxx – Gere pedidos GET, POST, etc. – Estes métodos podem ser reescritos para obter-se o comportamento desejado. • destroy – Chamado quando o servidor destrói uma instância da servlet. – Não é chamado em cada pedido 3 Servlet Life Cycle http://ltodi.est.ips.pt/leonardo/ci/M aterialA poio.htm Método init() O método init() é invocado quando a servlet é chamada pela primeira vez pelo browser. Não é chamado em pedidos seguintes. Usado para realizar inicializações. Existem duas versões do método init(): Versão 1: não possui argumentos Versão 2: tem como argumento um objecto do tipo servletConfig. 4 Servlet Life Cycle http://ltodi.est.ips.pt/leonardo/ci/M aterialA poio.htm 2 Exemplo Simple import java.io.*; import java.util.*; import javax.servlet.*; import javax.servlet.http.*; public class Birth extends HttpServlet { Date birthDate; // Init() is called first public void init() throws ServletException { birthDate = new Date(); } 5 Servlet Life Cycle http://ltodi.est.ips.pt/leonardo/ci/M aterialA poio.htm Exemplo Simple (cont.) // Handle an HTTP GET Request public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { response.setContentType("text/plain"); PrintWriter out = response.getWriter(); out.println ("I was born on: "+birthDate); out.close(); } } 6 Servlet Life Cycle http://ltodi.est.ips.pt/leonardo/ci/M aterialA poio.htm 3 Servlets Básico • Um modo de entender o funcionamento de um servlet é através da análise da figura, que representa um exemplo de um sistema clienteservidor baseado em servlets. 7 Servlet Life Cycle http://ltodi.est.ips.pt/leonardo/ci/M aterialA poio.htm Servlets Básico • no momento 1 um cliente envia uma requisição via HTTP; • no momento 2 o dispatcher carrega a servlet a partir de um repositório (caso o servlet1 ainda não esteja carregada); • no momento 3 a servlet1 recebe a requisição do cliente; • no momento 4 a servlet1 acede a uma base de dados; • no momento 5 os resultados da servlet1 são passados para a servlet2 • no momento 6 a servlet2 formata o resultado como uma página HTML e retorna esta página ao cliente 8 Servlet Life Cycle http://ltodi.est.ips.pt/leonardo/ci/M aterialA poio.htm 4 Instancia de uma Servlet A primeira vez que uma servlet é chamada, é criado uma instancia e o método init() é chamado. Apenas uma instancia da servlet é criada. Esta instancia é responsável por gerir todos os pedidos dos browser. 9 Servlet Life Cycle http://ltodi.est.ips.pt/leonardo/ci/M aterialA poio.htm Método Service() Para cada pedidos que o servidor recebe para uma servlet, o servidor lança uma nova thread e chama o método service. Browser Browser service() Web Server service() service() Single Instance of Servlet Browser 10 Servlet Life Cycle http://ltodi.est.ips.pt/leonardo/ci/M aterialA poio.htm 5 Exemplo: Explicação Exemplo: Servlet Contador; Regista informação sobre o número de vezes que uma servlet é acedida. Este exemplo mantêm uma única variável de instancia, chamada count. Cada vez que uma servlet é chamada a variável count é incrementada. Se o servidor criar uma nova instancia da da servelt para cada pedido então count terá sempre o valor 0! 11 Servlet Life Cycle http://ltodi.est.ips.pt/leonardo/ci/M aterialA poio.htm import java.io.*; import javax.servlet.*; import javax.servlet.http.*; •Apenas uma instância da servlet contador é criada. public class Counter extends HttpServlet { // Create an instance variable int count = 0; •Cada pedido do browser incrementa a mesma variável. // Handle an HTTP GET Request public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { response.setContentType("text/plain"); PrintWriter out = response.getWriter(); count++; out.println ("Since loading, this servlet has " + "been accessed "+ count + " times."); out.close(); } 12 } Servlet Life Cycle http://ltodi.est.ips.pt/leonardo/ci/M aterialA poio.htm 6 Método Service Por defeito o método service() verifica o cabeçalho HTTP. Com base nos cabeçalhos, o método faz uma chamada ao método com o mesmo nome do cabeçalho (doPost() ou doGet()). doPost ou doGet é o local onde é colocado a maior parte do código. 13 Se uma servlet necessita de processar ambos os tipos de pedidos então o método doPost() chama doGet() ou vice versa. Servlet Life Cycle http://ltodi.est.ips.pt/leonardo/ci/M aterialA poio.htm Sincronização de Thread Por defeito várias threads acedem a mesma servlet ao mesmo tempo. É necessário algum cuidado na sincronização o acesso aos dados que são partilhados. Por exemplo, o que acontece se dois browser solicitam uma um mesmo produto ao mesmo tempo. Sincronização é um tópico complexo. Existe uma solução para ultrapassar os problemas relacionados com os acesso simultâneos: SingleThreadModel… 14 Servlet Life Cycle http://ltodi.est.ips.pt/leonardo/ci/M aterialA poio.htm 7 Interface SingleThreadModel Para evitar o acesso multi-threaded a servlet deve implementar a interface SingleThreadModel: public class YourServlet extends HttpServlet implements SingleThreadModel { … } Isto garante que a servlet só ira processar um pedido de browser em cada instante. Com isto é resolvido a maior parte das questões relacionadas com a sincronização. Contudo, esta solução é pouco eficiente e resulta numa diminuição da performance, e por isto deve ser usado com bastante cuidado. 15 Servlet Life Cycle http://ltodi.est.ips.pt/leonardo/ci/M aterialA poio.htm Destruição de uma Servlet Antes de um servidor ser desligado ele faz uma chamada ao método destroy(). Várias operações de libertação de recursos devem ser feitas aqui: log files. Fecho de conecções a database. Fecho de conecções socket. 16 Servlet Life Cycle http://ltodi.est.ips.pt/leonardo/ci/M aterialA poio.htm 8 Exemplo: Death.java Proximo exemplo ilustra o uso do método destroy(). Quando está activa a servlet responde aos pedidos com a mensagem “Estou vivo !”. Quando o servidor é desligado, o método destroy() é chamadao, e a servlet armazena a hora da em que a servlet é destruida no ficheiro “rip.txt”. 17 Servlet Life Cycle http://ltodi.est.ips.pt/leonardo/ci/M aterialA poio.htm Exemplo: Death.java import java.io.*; import java.util.*; import javax.servlet.*; import javax.servlet.http.*; public class Death extends HttpServlet { // Handle an HTTP GET Request public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { response.setContentType("text/plain"); PrintWriter out = response.getWriter(); out.println ("I am alive!"); out.close(); Continua…. } 18 Servlet Life Cycle http://ltodi.est.ips.pt/leonardo/ci/M aterialA poio.htm 9 Exemplo: Death.java // This method is called when one stops // the Java Web Server public void destroy() { try { FileWriter fileWriter = new FileWriter ("rip.txt"); Date now = new Date(); String rip = "I was destroyed at: "+now.toString(); fileWriter.write (rip); fileWriter.close(); } catch (IOException e) { e.printStackTrace(); } } } 19 Servlet Life Cycle http://ltodi.est.ips.pt/leonardo/ci/M aterialA poio.htm Exemplo: rip.txt file Eu fui destruida em: Thu Aug 24 11:10:58 CDT 2000 20 Servlet Life Cycle http://ltodi.est.ips.pt/leonardo/ci/M aterialA poio.htm 10 Contador Persistente 21 import java.io.*; import java.util.*; import javax.servlet.*; import javax.servlet.http.*; •No Start-up, é carregado o contador de um ficheiro. public class CounterPersist extends HttpServlet { String fileName = "counter.txt"; int count; •Caso aconteça uma exception, o contador é inicializado a 0. public void init () { try { FileReader fileReader = new FileReader (fileName); BufferedReader bufferedReader = new BufferedReader (fileReader); String initial = bufferedReader.readLine(); count = Integer.parseInt (initial); } catch (FileNotFoundException e) { count = 0; } catch (IOException e) { count = 0; } Continua…. catch (NumberFormatException e) { count = 0; } } Servlet Life Cycle http://ltodi.est.ips.pt/leonardo/ci/M aterialA poio.htm Contador Persistente // Handle an HTTP GET Request public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { response.setContentType("text/plain"); PrintWriter out = response.getWriter(); count++; out.println ("Since loading, this servlet has " +"been accessed "+ count + " times."); Cada chamada a out.close(); doGet() incrementa a } variável count . Continua…. 22 Servlet Life Cycle http://ltodi.est.ips.pt/leonardo/ci/M aterialA poio.htm 11 Contador Persistente // At Shutdown, store counter back to file public void destroy() { try { FileWriter fileWriter = new FileWriter (fileName); String countStr = Integer.toString (count); fileWriter.write (countStr); fileWriter.close(); } catch (IOException e) { Quando destroy() é e.printStackTrace(); chamado é armazenado } o valor de counter em } counter.txt. } É possível existir algum problema com este código? 23 Servlet Life Cycle http://ltodi.est.ips.pt/leonardo/ci/M aterialA poio.htm 12