Servlet 3.0 ile gelen yenilikler

1997 yılında 1.0 versiyonu ile karşımıza çıkan Java Servlet spesifikasyonu, 10 Aralık 2009 tarihinde son sürümü olan Servlet 3.0 (JSR 315) ile kullanıcılarına merhaba dedi.  Java EE 6 spesifikasyonunun bir parçası olan Servlet 3.0 ile gelen yenilikler, daha önceki sürüm güncellemelerine kıyasla çok daha kapsamlı olması dikkat çekicidir. Bu yenilikler,  Servlet/Filter/Listener tabanlı çalışan tüm web frameworkların gidişatını değiştirecek şekilde etki etmesi beklenmektedir.

Servlet 3.0 ile gelen yenilikleri şöyle sıralandırabiliriz:

–          Servlet yazılımını kolaylaştırmak  (EoD)

–          Eklenebilirlik ve modülerlik

–          Asenkron çalışma desteği

–          Güvenlik ekleri

–          Diğer küçük ekler


Servlet yazılımını kolaylaştırmak

Bilindiği üzere, ne zaman bir servlet, filter veya listener yapmak istersek, önce gerekli java sınıflarını hazırlar ve ardından bunu web.xml içerisinde belirtiriz.  Bunu yapmazsak web container yazdığımız sınıfın bir servlet, filter veya listener sınıfı olduğunu otomatik olarak göremez.

Fakat Servlet 3.0 buna çok büyük bir kolaylık getirdi.

Servlet 3.0 spesifikasyonuyla beraber gelen yeni anotasyonlar sayesinde artık web.xml  gereksiz bir hale geldi

Bundan böyle tüm servlet, filter ve listener bilgilerini java sınıfı içerisine yazmamız mümkün.  Kullandığımız web container uygulamamızı load ederken, classpath içerisinde olan tüm anotasyonları tarar ve böylelikle dinamik bir biçimde bir çeşit web.xml dosyası hazırlar. İstenilirse bu tarama özelliğini kapatabiliriz ve tüm bilgiyi yine web.xml içerisine yazabiliriz. Bunu yapmak için web.xml içerisinde, metadata-complete özelliğine true değerini vermemiz gerekmektedir. (Standart olarak bu değer false`tır)

Bazı önemli anotasyonlar şunlardır:

–          @WebServlet

–          @WebFilter

–          @WebListener

–          @WebInitParam

–          @MultipartConfig


@WebServlet kullanımı:

@WebServlet(

name=“NewServlet”,

urlPatterns={“/NewServlet”},

initParams={

@WebInitParam(name=“value1″, value=“12345”),

@WebInitParam(name=“value2″, value=“67890”)

}

)

public class NewServlet extends HttpServlet {

@Override

protected void doGet(HttpServletRequest rq,HttpServletResponse rs)

throws ServletException, IOException {

}

}

@WebFilter kullanımı:

@WebFilter(
filterName=
“NewFilter”,

urlPatterns={“/test”}

)

public class NewFilter implements Filter {

public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException {

}

public void init(FilterConfig filterConfig) throws ServletException {

}

public void destroy() {

}

}

@WebListener kullanımı:

@WebListener()

public class NewServletListener implements ServletContextListener {

public void contextInitialized(ServletContextEvent sce) {

}

public void contextDestroyed(ServletContextEvent sce) {

}

}

@MultipartConfig kullanımı:

Bu anotasyon upload etmeyi kolaylaştırmış ve başka bir kütüphane kullanmayı gereksiz hale getirmiştir. HttpServletRequest sınıfına eklenen iki method sayesinde request objemizden direk olarak upload bilgilerini alabiliriz.  Bu iki method şunlardır:

–          getPart(String name)

–          getParts()

@MultipartConfig içinde kullanılmak üzere şu özellikler vardır:

–          fileSizeThreshold (dosya saklandıktan sonrakı threshold değeri)

–          maxRequestSize (en yüksek multipart/form-data requests değeri)

–          maxFileSize (en yüksek dosya büyüklüğü)

–          location (dosyanın saklanması gereken yer)

@MultipartConfig(location=”/ekler”, maxFileSize=5000)

public class NewServlet extends HttpServlet {

@Override

protected void doGet(HttpServletRequest rq,HttpServletResponse rs)

throws ServletException, IOException {

rq.getPart(“content”).write(“dosya.txt”);

}

}

Web.xml dosyasının gereksiz hale gelmesiyle beraber, bunun içinde bulunan diğer özellikler için de sabit değerlendirme getirilmiştir. Örneğin welcome-file-list standart olarak index.htm(l) ve index.jsp içermektedir.

Eklenebilirlik ve modülerlik

Servlet 3.0 spesifikasyonunun getirdiği en büyük yeniliklerden biri de, aynı zamanda Java EE 6’nın da ana temalarından biri olan ‘modülerlik’ özelliğidir

Yani istediğimiz herhangi bir framework veya kütüphaneyi kullanmak için sadece classpath’ımıza eklememiz yeterli olması ve hiç bir konfigürasyon detayını bilmek zorunda kalmamamızdır.

Günümüzde kullanılan web frameworkların hemen hemen hepsini, programımıza entegre etmek için yapmamız gereken şeylerin en başında, web.xml içerisinde bir takım eklemeler yapmaktır. Bu yöntem, modüler bir yapı düşüncesine tamamen ters düşmektedir. Çünkü ortada bir ana konfigürasyon dosyası (web.xml) var ve her framework/kütüphane eklemesinde bu dosyayı da güncellememiz gerekebilir.

Servlet 3.0 bu soruna ‘web-fragments’ ile bir çözüm getirdi. Web fragmenler, web.xml dosyasının dışarıdan eklenen bir parçası olarak görülebilir. Bundan böyle her framework/kütüphane, web.xml içerisine eklenmesi gereken tüm konfigürasyon bilgilerini, kendi web fragmentinde tutabilecek. Hazırladığınız web fragment dosyasının ismi web-fragments.xml olması ve jar dosyanızın META-INF klasorü içerisine konulması gerekmektedir. Listing 1 de örnek bir web fragmen dosyasını görmektesiniz.

<web-fragment>

<servlet>

<servlet-name>welcome</servlet-name>

<servlet-class>WelcomeServlet</servlet-class>

</servlet>

<listener>

<listener-class>RequestListener</listener-class>

</listener>

</web-fragment>

Listing 1 – web-fragment.xml (Web.xml içinde kullandığınız her öğeyi web-fragment dosyası içinde de kullanabilirsiniz.

Not: Web fragmenlerin web container tarafından load olma sırasını değiştirmek için de bazı ayarlar var. Bunları, kaynaklar da belirtilen servlet 3.0 spesifikasyonu pdf dosyasında görebilirsiniz.

Kod yardımıyla filter/listener/filter ekleme gibi işlemleri yapmak

Servlet 3.0 spesifikasyonuyla filter/listener/filter ekleme gibi işlemleri kod yardımıyla yapabilmek için, ServletContext sınıfına bazı methodlar eklendi. Bunlardan bazılarını şöyle sıralandırabiliriz;

–          addServlet(String servletName, String className)

–          getServletRegistrations()

–          addFilter(String filterName, String className)

–          getServletRegistrations()

–          void addListener(String className)

Bu methodları ne yazık ki her zaman kullanamazsınız. Sadece, programınızın initialization olması sırasında ve şu iki method içerisinde kullanabilirsiniz (Örnekler için listing 2’ye bakabilirsiniz):

–          ServletContextListener.contextInitialized(…)

–          ServletContainerInitializer.onStartup(…)

@WebListener

public class MyListener implements ServletContextListener {

public void contextInitialized(ServletContextEvent sce) {

ServletContext sc = sce.getServletContext();

sc.addServlet(“myServlet”, “Sample servlet”, “foo.bar.MyServlet”, null, -1);

sc.addServletMapping(“myServlet”, new String[] { “/urlpattern/*” });

}

}

@HandlesTypes(WebService.class)

public class JAXWSServletContainerInitializer implements ServletContainerInitializer {

public void onStartup(Set<Class<?>> c, ServletContext ctx)

throws ServletException {

ServletRegistration reg = ctx.addServlet(“JAXWSServlet”,

“com.sun.webservice.JAXWSServlet”);

reg.addServletMapping(“/foo”);

}

}

Listing 2

Asenkron desteği

Servlet 3.0 spesifikasyonunun getirdiği yeniliklerin arasında belkide en önemlisi asenkron çalışma desteğidir

Asenkron desteğini anlatmadan önce web sunucuların gelen istekleri nasıl işlediğini ve hangi yöntemleri kullandıklarını anlatmak istiyorum. Ardından asenkron çalışma sisteminin hangi sorunlara çözüm getirdiğine deyineceğim.

Her web sunucusu gelen istekleri en uygun şekilde işlemek için değişik yöntemler kullanır. Bunlardan bazıları thread-per-connection dediğimiz her bağlantı için bir thread atama yolunu seçer. Bazıları da thread-per-request dediğimiz her isteğe göre bir thread atama yolunu seçer.

Thread-per-connection yöntemi

Bu yöntem her bağlantıya, işlem olsun olmasın bir thread atar. Yani o bağlantı içinde bir işlem olmasa bile, thread bağlantı kapanana kadar orada kilitli (locked) kalır. Bağlantı kapandıktan sonra bu thread temizlenir ve diğer bir bağlantı için kullanılmak üzere thread havuzuna döner. Bu yöntemin dezavantajı, threadlerin uygun şekilde kullanılmaması ve işlem olmadığı zamanlarda gereksiz yere bekletilmesidir. Thread yaratmanın ve yok etmenin ne kadar pahalı bir işlem olduğunu göz önünde bulundurursak bu yöntem pek uygun olduğu söylenemez.

Thread-per-request yöntemi

Bu yöntem thread-per-connection`da olduğunun aksine, sadece bağlantı içinde bir işlem olduğu zaman bir thread atar ve o işlem biter bitmez bu thread tekrar thread havuzuna döner. Yani bağlantının kapanmasını beklemez. Bu sayede web sunucusu daha iyi genişleyebilir ve daha çok bağlantıya karşılık verebilir. Bu yöntem günümüzde bir çok popüler web sunucuları tarafından kullanılmaktadır. Örneğin WebLogic, GlassFish, Tomcat, Websphere.

Yukarıda gördüğümüz yöntemlerden bağımsız olarak servlet kullanmanın bazı eksi yanları var. Bunların en başında, servlet`imizin dış bir kaynağa bağlı olarak uzun süre beklemesi ve cevap gelene kadar kilitli kalması. Bir örnek vermek gerekirsek: “yazdığımız servlet içinde bir webservis çağırabiliriz ve cevap gelmesi çok uzun sürebilir, veya jdbc ile veritabanından bilgi çekebiliriz ve bu da uzun sürebilir”.  Yani dış kaynaklardan cevap gelmediği sürece, servlet`a gereksiz yere beklemektedir ve bu sayede de web sunucusu kısa süre içersinde yeni gelen isteklere karşılık veremez hale gelebilir.

İşte Servlet 3.0 ile gelen asenkron çalışma desteği bu soruna tam çözüm sağlıyor. Artık dış kaynaklara bağlı uzun bekleme durumunda, servlet kilitli kalmıyor ve hemen yeni isteklerde kullanılabiliyor. Dış kaynaktan bilgi geldiği anda işlem devam ediyor ve istenildiği gibi bir response gönderilebiliyor. Böylelikle servlet`ler en uygun bir şekilde kullanılmış oluyor.

Asenkron desteği yalnızca @WebServlet ve @WebFilter için mevcut ve bunu aktif hale getirmek için asyncSupported özelliğine true değerini vermeniz gerekmektedir. Böylelikle servlet`e bağlı olan response objesi commit edilmez.

Asenkron çalışma için AsyncContext adında yeni bir sınıf eklenmiştir ve bu sınıf sayesinde tüm request ve response objelerimizin yaşam döngüsü yönetilebiliyor. Bunun yanında AsynContext objesini yaratmak için de ServletRequest sınıfına 2 yeni method eklenmiştir.

  1. 1. startAsync(ServletRequest req, ServletResponse res)  -> İstenilen her hangi bir request ve response için asenkron işlem başlatır.
  2. 2. startAsync()  -> Orjinal request ve response için asenkron işlem başlatır.

Öncelikle yapmamız gereken request objesini kullanarak yeni bir AsyncContext objesi yaratmak. Ardından da bu yaratılan objeyi işlenmek üzere bir çeşit queue içine atmak. Bu queue diger bir process tarafından sürekli okunup yeni bir thread tarafından işlenir. Bu sayede servlet, doGet methodundan çıkar ve yeni istekleri karşılamak için web sunucusuna geri döner.  Listing 3`de bir örnek görebilirsiniz.

@WebServlet(

name=”NewServlet”,

urlPatterns={“/NewServlet”},

initParams={

@WebInitParam(name=”value1″, value=”12345″),

@WebInitParam(name=”value2″, value=”67890″)

},

asyncSupported=true

)

public class NewServlet extends HttpServlet {

@Override

protected void doGet(HttpServletRequest rq,HttpServletResponse rs)

throws ServletException, IOException {

//asenkron calisma basliyor

AsyncContext aCtx = rq. (rq, rs);

ScheduledThreadPoolExecutor executor = new ThreadPoolExecutor(10);

executor.execute(new BenimAsyncWebServisim(aCtx));

}

}

public class BenimAsyncWebServisim implements Runnable {

AsyncContext ctx;

public BenimAsyncWebServisim(AsyncContext ctx) {

this.ctx = ctx;

}

public void run() {

ctx.dispatch(“/ayarla.jsp”);

}

}

Listing 3

Güvenlik ekleri

Servlet 3.0 spesifikasyonuyla beraber, program koduyla login yapabilmek için HttpServletRequest sınıfına login methodu eklendi ve logout yapabilmek için HttpSession ve HttpServletRequest sınıflarına logout methodu eklendi.

Diğer küçük ekler

Servlet 3.0 ile gelen bir ekleme sayesinde çerezlerimizi (Cookies) HttpOnly diye belirtebiliriz. Böylelikle çerezlerimiz kullanıcı tarafındaki scripting kodları tarafından erişilemez hale getiririz ve cross-site scripting ataklarını önleyebiliriz.

Kaynaklar:

http://jcp.org/en/jsr/detail?id=315 (JSR 315: JavaTM Servlet 3.0 Specification)
http://today.java.net/article/2008/10/08/introduction-servlet-30
http://www.javaworld.com/javaworld/jw-02-2009/jw-02-servlet3.html

Share this Story

Related Posts

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>