Na samom početku ove priče napravit ćemo jedan mali historijski pregled i pokušati shvatiti potrebu za servletima.

Početkom 50-ih godina američki naučnici su uložili mnogo truda da bi bili rame uz rame sa tadašnjim Sovjetskim savezom u oblasti računarstva i kompjuterske nauke. U tu svrhu 1957. godine su osnovali poseban tim ARPA (Advanced Research Projects Agency) koji se bavio naučnim istraživanjma u oblasti informatike. Iako su u to vrijeme imali najsavremeniju opremu i veoma snažnu kompjutersku moć sami računari nisu mogli komunicirati između sebe što je predstavljalo jedan od velikih izazova koje je bilo potrebno riješiti. Sredinom 60tih godina, tačnije 1966 Lawrence G. Roberts je odlučio da rijesi taj problem i predložio je dizajn prve kompjuterske mreže zvanu ARPANET. Pod pokrviteljstvom američkog odjela za odbranu (US Department of Defense) 3 godine poslije implementiran je ARPANET, prva kompjuterska mreža koja radi na principu razmjene paketa i time omogućio komunikaciju između računara.

Pravi uspjeh desio se 1982. kada su Vint Cerf i Bob Kahn implementirali TCP/IP standard i kada je DNS(Domain Name System) uspostavljen. Do kraja 1984. godine registrovano je preko 1000 hostova.

Početkom 90ih godina Tim Berners Lee je predstavio pojam hiperlinkova tj. napravio je cijeli protokol (http) preko kojeg se i do danasnjeg dana vrši razmjena podataka. World Wide Web(www) je rođen a sve ostalo je historija.

Premotat ćemo malo film unaprijed u vrijeme kada statičke stranice nisu bile dovoljne korisnicima i kada se javila potreba za dinamičkim sadržajem. Za prikaza dinamičkog sadržaja koristio se CGI (Common Gateway Interface).

CGI

Common gateway interface, u nastavku CGI, je takoreći jedna od prvih tehnika za kreiranje dinamičkih web aplikacija. Koristeći CGI, zahtjev koji dođe od klijeta web server proslijedi do externog programa (cgi script). Rezultat ovog poziva šalje se nazad korisniku u vidu statičkog fajla. Prednost CGI-a bila je ta što se moglo implementirati različite funkcionalnosti i brzo je postao de facto standard. 

 
Jedan od najvećih problema CGI-a jesu njegove performanse koje su bile dosta loše. Kada server primi zahtjev za nekom od CGI skripti on mora kreirati novi proces da bi pokrenuo program i proslijediti mu sve podakte preko environment varijabli koje su potrebne za generisanje odgovora. Kreiranje procesa za svaki ovakav zatjev je preveliko opterećenje za server, također dolazi do ograničenja broja zahtjeva za paralelno obrađivanje što dovodi do zastoja servera.
 
 

Servleti

Nakon svih problema sa CGI kao pravi nasljednik na scenu stupaju servleti. Iako je java programski jezik konceptualiziran 1991. godine njena namjena nije bila tzv. internet programiranje sve dok se 1997. godine nisu pojavili servleti. Nastali su kao alternativa CGI i u mnogo stvari su bili bolji od konkurencije. Najveća prednost je bila to što su za svaki zahtjev otvarali java thread sto je sa aspekta performansi puno bolje od kreiranja novog procesa za svaki zahtjev. Zahvaljujući svojoj arhitekturi servleti su mogli podnijeti veliko opterecenje i time postali broj jedan u svijetu web developmenta.

Pored poboljšanja u performansama servleti su imali još jednu veliku prednost. S obzirom da servleti koriste javu kao programski jezik ovdje vazi sve isto kao i kod jave. Dakle nezavisni su od platforme i mogu se deploy-ati na različite operativne sisteme i web servere. U suštini servlet predstavlja običnu java klasu koja se izvršava na JVM-u (Java Virtual Machine).

Servlet predstavlja java objekat koji obradjuje http requeste i izvršava se unutar servlet kontejnera. Kontejneri se obično nalaze unutar web servera kao što su Tomcat, Jetty i mnogi drugi.

 
Kada zahtjev dođe sa browsera prema servlet kontejneru, on na osnovu konfiguracije odluči koji servlet da pozove. Servlet se aktivira pozivom service() metode a ona obrađuje poslani request i generiše response nazad u browser.

Servlet life cycle

Kao sve u životu i servleti imaju svoj životni ciklus koji je orkestriran od strane kontejnera. Ciklus se sastoji od sljedećih koraka:

1. Load-anje servlet klase.
2. Kreiranje instance servleta.
3. Inicijalizacija servleta. Poziv init() metode.
4. Poziv service() metode.
5. Uništavanje, poziv destroy() metode.

  

Koraci 1, 2 i 3 se dešavaju pri samom pokretanju aplikacije load-aju se sve potrebne klase. Kada je servlet klasa load-ana, kontejner kreira instancu servlet klase (korak 2). Priliko kreiranja instance poziva se init() metoda koja omogućava da se servlet inicijalizira prije obrade prvog zahtjeva.

Za svaki napravljeni zahtjev poziva se service() metoda i sve dok je servlet aktivan mogućnost poziva ove metode je otvorena.

Servlet kontejner poziva destroy() metodu kako bi naznačio da servlet nece vise biti dostupan i poziv service() metode nad ovim servletom vise neće biti moguć. Ovo se često desava prilikom restarta ili gašenja aplikacije.

Primjer

Recimo da želimo da napravimo servlet koji se poziva prilikom logiranja na stranicu. Da bi napravili servlet moramo kreirati klasu koja će extend-ati jednu od dvije abstraktne klase: GenericServlet ili HttpServlet. Osnovna razlika je, kao što i samo ime kaže, http servlet se koristi samo za http protokol dok generic servlet pruža podršku i za ostale protokole. Za naš slučaj mi ćemo koristiti http servlet.

import java.io.*; 
import javax.servlet.*; 
import javax.servlet.http.*;

public class MyPersonalServlet extends HttpServlet { 

   public void doGet(HttpServletRequest request,HttpServletResponse response) throws 
                   ServletException, IOException { 
   // Do some login logic...
   } 
} 


U konfiguraciji java web aplikacije navedemo mapiranje koje će servlet kontejneru reći kada koji servlet da poziva. Ova konfiguracija se čuva u web.xml i izgleda ovako:


 

Kada klijent otvori sljedeći URL kroz browser: http://localhost:8080/ServletDemo/myPage
request će doći prvo do servlet kontejnera koji će prema mapiranju iz web.xml fajla pozvati naš LoginServlet i odraditi njegovu doGet metodu. Nakon toga izgenerisat će se response objekat i vratiti nazad na browser klijentu.

Spring dispatcher servlet

Front controller dizajn patern predstavlja centralizovani mehanizam za obrađivanje zahtjeva. Spring dispatcher servlet implementira ovaj patern i kao takav je zaslužan za obradjivanje svih http zahtjeva. Zvuči poznato? Dispatcher servlet je kao i svaki drugi servlet, on se mora definisati u konfiguraciji aplikacije (web.xml). Da bi postigli gore navedeno ponašanje konfiguracija bi trebala izgledati ovako:


Dakle iz konfiguracije možemo vidjeti da svaki zahtjev što dodje na server dolazi do dispatcher servleta na obradu. 

 

Šta se sve dešava ‘pod haubom’ spring dispatcher servleta vidjet ćemo kroz sljedeći primjer. Imamo kontroler:

@Controller
@RequestMapping("/appointments")
public class AppointmentsController {

    private final AppointmentBook appointmentBook;
    
    @Autowired
    public AppointmentsController(AppointmentBook appointmentBook) {
        this.appointmentBook = appointmentBook;
    }

    @RequestMapping(method = RequestMethod.GET)
    public Map get() {
        return appointmentBook.getAppointmentsForToday();
    }

    @RequestMapping(value="/{day}", method = RequestMethod.GET)
    public Map getForDay(@PathVariable @DateTimeFormat(iso=ISO.DATE) Date day, Model model) {
        return appointmentBook.getAppointmentsForDay(day);
    }

    @RequestMapping(value="/new", method = RequestMethod.GET)
    public AppointmentForm getNewForm() {
        return new AppointmentForm();
    }

    @RequestMapping(method = RequestMethod.POST)
    public String add(@Valid AppointmentForm appointment, BindingResult result) {
        if (result.hasErrors()) {
            return "appointments/new";
        }
        appointmentBook.addAppointment(appointment);
        return "redirect:/appointments";
    }
}

Kotroler obezbjeđuje pristup aplikaciji, interpretira korisnikov zahtjev i obrađeni zahtjev vraća nazad korisniku.

Prva stvar koju možemo primjetiti jesu ove dvije anotacije @Controller i @RequestMapping. @Controller kao što i sama riječ kaže naznačava da ova klasa obavlja funkciju kontrolera dok @RequestMapping url kao što je /appointments vrši mapiranje na cijelu klasu.

Kada korisnik unese url http:localhost:8080/appointments/new u browser, zahtjev dolazi do dispatcher servleta. Servlet prihvati zahtjev i ulazi u proces resolvanja zahtjeva. Dispatcher, koristeći HandlerMapping klasu, skenira sve klase sa anotacijom @Controller i pronalazi odgovarajući kontroler za odgovarajući mapping(/appointments/new). Zahtjev odlazi do kontrolera gdje se vrši potrebna obrada i nakon obrade vraća se nazad u vidu modela u dispatcher servlet. Dobiveni model servlet šalje u ViewResolver klasu gdje se iz zahtjeva (appointments/new) resolva stvarni .jsp file. Na kraju dispatcher servlet dobiveni jsp šalje nazad korisniku.


U današnjoj upotrebi spring/spring boot-a detalji resolvanja zahtjeva ostaju skriveni i često postajaju nepoznanica samim korisnicima ovih alata. Ukoliko želite saznati nešto više o ovome detalje možete pronaći na spring-ovoj dokumentaciji ovdje : https://docs.spring.io/spring/docs/3.0.x/spring-framework-reference/html/mvc.html#mvc-handlermapping-interceptor

Do narednog čitanja.

Admir Oković, Infobip BH d.o.o.

1/1