Sunucu uygulamaları nasıl çalışır? Örnekleme, oturumlar, paylaşılan değişkenler ve çoklu kullanım


1144

Varsayalım, çok sayıda sunucu uygulaması olan bir web sunucum var. Bu sunucu uygulamaları arasında geçen bilgiler için oturum ve örnek değişkenleri ayarlıyorum.

Şimdi, 2 veya daha fazla kullanıcı bu sunucuya istek gönderirse, oturum değişkenlerine ne olur?
Hepsi tüm kullanıcılar için ortak mı olacak yoksa her kullanıcı için farklı mı olacak?
Farklılarsa, sunucu farklı kullanıcılar arasında nasıl ayrım yapabiliyordu?

Benzer bir soru, eğer nbelirli bir sunucu uygulamasına erişen kullanıcılar varsa , bu sunucu uygulaması sadece ilk kullanıcı ona ilk kez eriştiğinde mi yoksa tüm kullanıcılar için ayrı olarak mı örneklenir?
Başka bir deyişle, örnek değişkenlerine ne olur?

Yanıtlar:


1821

ServletContext'te

Sunucu uygulaması kapsayıcısı ( Apache Tomcat gibi ) başladığında, tüm web uygulamalarını dağıtır ve yükler. Bir web uygulaması yüklendiğinde sunucu uygulaması kapsayıcısı bir ServletContextkez oluşturur ve sunucunun belleğinde tutar. Web uygulaması en web.xmlve dahil tüm web-fragment.xmldosyaların çözümlenen ve her edilir <servlet>, <filter>ve <listener>bulunan (veya her sınıf ile açıklamalı @WebServlet, @WebFilterve @WebListenersırasıyla) bir kez örneği ve sunucunun bellekte tutulur yanı edilir. Her somutlaştırılmış filtre için init()yöntemi yeni bir yöntemle çağrılır FilterConfig.

Bir zaman Servletbir sahiptir <servlet><load-on-startup>ya da @WebServlet(loadOnStartup)daha değeri daha büyük 0, daha sonra init()yöntem, aynı zamanda, yeni bir başlatma sırasında çağrılır ServletConfig. Bu sunucu uygulamaları (o değere göre belirtilen sırayla başlatılır 11 olduğu, 22nd, vb). Aynı değeri birden fazla sunucu uygulaması belirtilirse bu görünür şekilde, o zaman bu servlet her biri aynı sırayla yüklenir web.xml, web-fragment.xmlya da @WebServletclassloading. "Başlangıçta yükleme" değeri yoksa, init()HTTP isteği bu sunucu uygulamasına ilk kez ulaştığında yöntem çağrılır.

Sunucu uygulaması kabı yukarıda açıklanan başlatma adımlarının tümü ile bittiğinde, servis ServletContextListener#contextInitialized()çağrılır.

Aşağı sunucu uygulaması kap kapanır, tüm internet uygulamaları kaldırır, çağırır destroy()onun başlatıldı servlet ve filtreler, ve tüm yöntemi ServletContext, Servlet, Filterve Listenerörnekler çöpe atılan. Sonunda ServletContextListener#contextDestroyed()çağrılacak.

HttpServletRequest ve HttpServletResponse

Sunucu uygulaması kapsayıcısı, belirli bir bağlantı noktası numarasındaki HTTP isteklerini dinleyen bir web sunucusuna eklenir (bağlantı noktası 8080 genellikle geliştirme sırasında ve bağlantı noktası üretim sırasında 80 kullanılır). Bir istemci (örneğin, bir web tarayıcısı olan veya programlı olarak kullanan bir kullanıcıURLConnection ) bir HTTP isteği gönderdiğinde, sunucu uygulaması kapsayıcısı yeni oluşturur HttpServletRequestve HttpServletResponsenesneler oluşturur ve bunları Filterzincirde ve nihayetinde Servletörnekte tanımlananlardan geçirir .

Filtre durumunda , doFilter()yöntem çağrılır. Sunucu uygulaması kabının kodu aradığında chain.doFilter(request, response), istek ve yanıt bir sonraki filtreye devam eder veya kalan filtre yoksa sunucu uygulamasına vurur.

Sunucu uygulamaları durumunda , service()yöntem çağrılır. Varsayılan olarak, bu yöntem hangi doXxx()yöntemlerden hangisinin kullanılacağını belirler request.getMethod(). Belirlenen yöntem sunucu uygulamasında yoksa, yanıtta bir HTTP 405 hatası döndürülür.

İstek nesnesi, URL isteği, üstbilgileri, sorgu dizesi ve gövdesi gibi HTTP isteğiyle ilgili tüm bilgilere erişim sağlar. Yanıt nesnesi, HTTP yanıtını istediğiniz şekilde kontrol etme ve gönderme olanağı sağlar; örneğin, üstbilgileri ve gövdeyi (genellikle bir JSP dosyasından oluşturulan HTML içeriğiyle) ayarlamanıza olanak tanır. HTTP yanıtı tamamlandığında ve bittiğinde, hem istek hem de yanıt nesneleri geri dönüştürülür ve yeniden kullanılabilir hale getirilir.

HttpSession

Bir istemci web uygulamasını ilk kez ziyaret ettiğinde ve / veya HttpSessionaracılığıyla ilk kez request.getSession()alındığında, sunucu uygulaması kapsayıcısı yeni bir HttpSessionnesne oluşturur, uzun ve benzersiz bir kimlik oluşturur (bunu elde edebilirsiniz session.getId()) ve bunu sunucuda depolar. hafıza. Sunucu uygulaması bir konteynır setleri Cookiede Set-CookieHTTP yanıtı başlığında JSESSIONIDadını ve değer olarak benzersiz bir oturum numarası olarak.

Gereğince HTTP çerezi şartnamede (sözleşme uymalıdır herhangi nezih bir web tarayıcı ve web sunucusu), istemci (web tarayıcısı) 'de daha sonraki isteklerinin bu çerez geri göndermek için gerekli olan Cookieuzun çerez geçerli olduğu kadar için başlığındaki ( başka bir deyişle, benzersiz kimlik süresi dolmamış bir oturuma başvurmalıdır ve alan ve yol doğru olmalıdır). Tarayıcınızın yerleşik HTTP trafik izleyicisini kullanarak, çerezin geçerli olduğunu doğrulayabilirsiniz (Chrome / Firefox 23+ / IE9 + 'da F12 tuşuna basın ve Net / Ağ sekmesini kontrol edin ). Sunucu uygulaması kapsayıcısı, Cookiegelen her HTTP isteğinin başlığını, adıyla birlikte çerezin olup olmadığını kontrol eder JSESSIONIDve HttpSessionsunucunun belleğinden ilişkilendirmek için değerini (oturum kimliği) kullanır .

HttpSessionBunun kadar hayatta kalır fazlasında belirtilen zaman aşımı değerinden daha için (yani bir istek kullanılmaz) boşta <session-timeout>bir ayar web.xml. Zaman aşımı değeri varsayılan olarak 30 dakikadır. Bu nedenle, istemci web uygulamasını belirtilen süreden daha uzun süre ziyaret etmediğinde, sunucu uygulaması kapsayıcısı oturumu çöp kutusuna atar. Takip eden her istek, tanımlama bilgisi belirtilmiş olsa bile, artık aynı oturuma erişemeyecektir; sunucu uygulaması kapsayıcısı yeni bir oturum oluşturur.

İstemci tarafında, oturum çerezi tarayıcı örneği çalıştığı sürece canlı kalır. Bu nedenle, istemci tarayıcı örneğini kapatırsa (tüm sekmeler / pencereler), oturum istemci tarafında çöpe atılır. Yeni bir tarayıcı örneğinde, oturumla ilişkilendirilmiş çerez mevcut olmaz, bu yüzden artık gönderilmez. Bu HttpSession, tamamen yeni bir oturum çerezi kullanılarak tamamen yeni bir yaratılmasına neden olur .

Kısaca

  • ServletContextSürece web uygulaması hayatları olduğunca yaşıyor. Tüm oturumlardaki tüm istekler arasında paylaşılır .
  • HttpSessionUzun istemci aynı tarayıcı örneği ile web uygulaması ile etkileşim ve oturum sunucu tarafında aşımına henüz olduğunca için yaşıyor. Aynı oturumdaki tüm istekler arasında paylaşılır .
  • HttpServletRequestVe HttpServletResponseservlet istemciden bir HTTP isteği alır zaman canlı, tam cevap (web sayfası) gelinceye kadar. O edilir değil başka yerde paylaştı.
  • Tüm Servlet, Filterve Listenerörnekleri sürece web uygulaması yaşadıkça yaşar. Tüm oturumlardaki tüm talepler arasında paylaşılırlar .
  • Herhangi attributetanımlanmış olduğunu ServletContext, HttpServletRequestve HttpSessionsoru hayatımızda nesne sürece yaşayacaktır. Nesnenin kendisi JSF, CDI, Bahar, vb. Gibi fasulye yönetim çerçevelerindeki "kapsamı" temsil eder. Bu çerçeveler attributekapsam dahilindeki çekirdeklerini en yakın eşleşen kapsamı olarak depolar .

İplik Güvenliği

Bununla birlikte, büyük endişeniz muhtemelen iplik güvenliği . Artık sunucu uygulamaları ve filtrelerin tüm istekler arasında paylaşıldığını bilmelisiniz. Java ile ilgili güzel bir şey, çok iş parçacıklı ve farklı iş parçacıkları (okuma: HTTP istekleri) aynı örneği kullanabilir. Aksi halde yeniden oluşturmak çok pahalı olurdu init()ve destroy()her istek için onları.

Ayrıca, herhangi bir istek veya oturum kapsamındaki verileri asla bir sunucu uygulamasının veya filtrenin örnek değişkeni olarak atamamanız gerektiğini de bilmelisiniz . Diğer oturumlardaki diğer tüm talepler arasında paylaşılacaktır. Bu güvenli değil ! Aşağıdaki örnek bunu göstermektedir:

public class ExampleServlet extends HttpServlet {

    private Object thisIsNOTThreadSafe;

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        Object thisIsThreadSafe;

        thisIsNOTThreadSafe = request.getParameter("foo"); // BAD!! Shared among all requests!
        thisIsThreadSafe = request.getParameter("foo"); // OK, this is thread safe.
    } 
}

Ayrıca bakınız:


25
Yani bir şekilde bir istemciye gönderilir JSessionId bulabilirim, ben onun oturumunu çalabilir?
Kasım'da Toskan

54
@Toskan: Doğru. Oturum sabitleme kesmek olarak bilinir . Lütfen bunun JSP / Servlet'e özgü olmadığını unutmayın. Oturumu bir çerezle koruyan diğer tüm sunucu tarafı dilleri de hassastır, örneğin çerezli PHP , çerezli PHPSESSIDASP.NET ASP.NET_SessionID, vb. Bu nedenle ;jsessionid=xxx, bazı JSP / Servlet MVC çerçevelerinin otomatik olarak yaptığı gibi URL yeniden yazmanın da kaşlarını çattı. Oturum kimliğinin hiçbir zaman URL'de veya web sayfalarında başka yollarla açıkta kalmamasını sağlayın, böylece habersiz son kullanıcıya saldırılmaz.
BalusC

11
@Toskan: Ayrıca, web uygulamanızın XSS saldırılarına karşı hassas olmadığından emin olun. Kullanıcı kontrolündeki herhangi bir girişi kaçış formunda tekrar görüntülemez. XSS, kapıları tüm son kullanıcıların oturum kimliklerini toplama yollarına açık hale getirir. Ayrıca bkz. XSS'in ardındaki genel kavram nedir?
BalusC

2
@BalusC, Aptallığım için özür dilerim. Bu, tüm kullanıcıların buIsNOTThreadSafe ile aynı örneğe eriştiği anlamına mı geliyor?
gölgede

4
Tüm sunucu uygulamasının kendisi olmadığında @TwoThumbSticks 404 döndürülür. Sunucu uygulaması mevcutken 405 döndürülür, ancak istenen doXxx () yöntemi uygulanmaz.
BalusC

428

Oturumlar

resim açıklamasını buraya girin resim açıklamasını buraya girin

Kısaca: Web sunucusu için benzersiz bir tanımlayıcı sorunları her ziyaretçi yaptığı üzerinde ilk ziyareti. Ziyaretçi, bir dahaki sefere tanınması için bu kimliği geri getirmelidir. Bu tanımlayıcı ayrıca sunucunun bir oturumun sahip olduğu nesneleri diğerinin oturumuna göre doğru şekilde ayırmasına izin verir.

Sunucu Uygulaması Örneği

Eğer yük-on-başlatma olduğu yanlış :

resim açıklamasını buraya girin resim açıklamasını buraya girin

Eğer yük-on-başlatma olduğu doğrudur :

resim açıklamasını buraya girin resim açıklamasını buraya girin

Servis moduna ve oluğa girdikten sonra, aynı sunucu uygulaması diğer tüm istemcilerden gelen talepler üzerinde çalışacaktır.

resim açıklamasını buraya girin

Müşteri başına bir örneğe sahip olmak neden iyi bir fikir değil? Bunu bir düşünün: Gelen her sipariş için bir tane pizza kiralayacak mısınız? Bunu yapın ve hiçbir zaman işiniz biter.

Yine de küçük bir riskle geliyor. Unutmayın: bu tek adam tüm sipariş bilgilerini cebinde tutar: bu nedenle , sunucu uygulamalarında iplik güvenliği konusunda temkinli değilseniz , belirli bir müşteriye yanlış sipariş verebilir.


26
Resmim kavrayışım için çok iyi. Bir sorum var, bu pizza restoranı çok fazla pizza siparişi geldiğinde ne yapacak, sadece bir pizza adamı bekle veya daha fazla pizza kirala? Teşekkürler .
zh18

6
Oto many requests at this moment. try again later
Please_Dont_Bully_Me_SO_Lords

3
Servletler, Pizza dağıtım insanlarının aksine, aynı anda birden fazla teslimat yapabilir. Onlar sadece müşterinin adresini, pizzanın lezzetini yazdıkları yere özel özen göstermeliler ...
Bruno

42

Java sunucu uygulamalarındaki oturum, PHP gibi diğer dillerde oturumla aynıdır. Kullanıcıya özgüdür. Sunucu, çerezler, url yeniden yazma vb. Gibi farklı şekillerde takip edebilir. Bu Java dokümanı makalesi, Java sunucu uygulamaları bağlamında açıklar ve oturumun tam olarak nasıl korunduğunu sunucunun tasarımcılarına bıraktığı bir uygulama detayı olduğunu belirtir. Belirtim yalnızca, sunucuya birden çok bağlantı üzerinden kullanıcının benzersiz olarak korunması gerektiğini belirtir. Check out Oracle bu makaleyi sorularınızın ikisi hakkında daha fazla bilgi için.

Düzenle Burada sunucu uygulamalarının içinde oturum ile nasıl çalışılacağı konusunda mükemmel bir öğretici var . Ve burada olduklarını ve nasıl kullanılacakları ne Java Servlet, yaklaşık Güneş'ten bir bölüm. Bu iki makale arasında tüm sorularınızı cevaplayabilmeniz gerekir.


Bu benim için başka bir soru getiriyor, Tüm uygulama için sadece bir sunucu uygulaması olduğundan ve oturum değişkenlerine bu sunucu uygulamasıyla erişebildiğimizden, oturum değişkenleri her kullanıcıya nasıl benzersiz olabilir? Teşekkürler ..
Ku Jon

1
servletContext oturumuna nasıl erişiyorsunuz? ServletContext.setAttribute () 'a başvurmuyorsunuz, değil mi?
matt b

4
@KuJon Her web uygulamasının bir ServletContextnesnesi vardır. Bu nesnenin sıfır, bir veya daha fazla oturum nesnesi vardır - oturum nesneleri koleksiyonu. Her oturum, diğer cevaplardaki karikatürlerde görüldüğü gibi bir tür tanımlayıcı dize ile tanımlanır. Bu tanımlayıcı, çerez veya URL yeniden yazma yoluyla istemcide izlenir. Her oturum nesnesinin kendi değişkenleri vardır.
Basil Bourque

33

Sunucu uygulaması kapsayıcısı (Apache Tomcat gibi) başlatıldığında, bir şey ters giderse veya kapsayıcı tarafı konsolunda bir hata gösterirse web.xml dosyasından (uygulama başına yalnızca bir tane) okunur, aksi takdirde tüm ağı dağıtır ve yükler web.xml (dağıtım tanımlayıcısı olarak adlandırılır) kullanarak uygulamalar.

Sunucu uygulamasının örnekleme aşaması sırasında sunucu uygulaması örneği hazırdır, ancak iki bilgi eksik olduğu için istemci isteğine hizmet edemez:
1: bağlam bilgisi
2: başlangıç ​​yapılandırma bilgileri

Servlet altyapısı, yukarıdaki eksik bilgileri içine alan servletConfig arabirim nesnesi oluşturur ve servlet engine, inlet () işlevini sunucu uygulamasının argüman olarak argümanlarını sağlayarak çağırır. İnit () tamamen yürütüldüğünde, sunucu uygulaması istemci isteğini sunmaya hazırdır.

S) Servlet ömrü boyunca örnekleme ve başlatma kaç kez olur?

A) yalnızca bir kez (her istemci isteği için yeni bir iş parçacığı oluşturulur) sunucu uygulamasının yalnızca bir örneği herhangi bir sayıda istemci isteğine hizmet eder, yani bir istemci istek sunucusuna hizmet verdikten sonra ölmez. Diğer istemci isteklerini, yani sunucu uygulamasıyla hangi CGI (her istemci isteği için yeni bir işlem oluşturulur) sınırlamasının aşılmasını bekler (dahili olarak sunucu uygulaması iş parçacığı oluşturur).

S) Oturum kavramı nasıl çalışır?

A) HttpServletRequest nesnesinde getSession () çağrıldığında

Adım 1 : İstek nesnesi gelen oturum kimliği için değerlendirilir.

Adım 2 : ID yoksa, yepyeni bir HttpSession nesnesi oluşturulur ve karşılık gelen oturum kimliği oluşturulur (yani HashTable) oturum kimliği httpservlet yanıt nesnesine depolanır ve HttpSession nesnesinin başvurusu sunucu uygulamasına (doGet / doPost) döndürülür .

Adım 3 : ID kullanılabilir yepyeni oturum nesnesi oluşturulmazsa oturum kimliği, istek olarak oturum nesnesi toplanır ve oturum koleksiyonunda anahtar olarak oturum kimliği kullanılarak arama yapılır.

Arama başarılı olduğunda oturum kimliği HttpServletResponse içinde depolanır ve varolan oturum nesnesi başvuruları UserDefineservlet'in doGet () veya doPost () öğesine döndürülür.

Not:

1) denetim sunucu uygulamacığı kodundan istemciye ayrıldığında, oturum nesnesinin sunucu uygulaması kabı tarafından tutulduğunu unutmayın, yani sunucu uygulaması motoru

2) çok iş parçacığı uygulama uygulamak için insanlara sunucu uygulaması geliştiricilere bırakılır.

Kısa form:

Uygulama başlatıldığında (sunucu uygulaması kapsayıcısında dağıtıldığında) veya sunucu uygulaması başlatıldığında ilk kez erişildiğinde (başlangıçtaki yükleme ayarına bağlı olarak) bir sunucu uygulaması oluşturulur, sunucu uygulamasının init () yöntemi çağrılır ardından sunucu uygulaması (tek ve tek örneği) tüm istekleri (birden çok iş parçacığı tarafından çağrılan service () yöntemi) işler. Bu nedenle içinde herhangi bir senkronizasyon olması önerilmez ve uygulama dağıtılmadığında (sunucu uygulaması kapsayıcı durur), destroy () yöntemi çağrıldığında sunucu uygulamasının örnek değişkenlerinden kaçınmalısınız.


20

Oturumlar - Chris Thompson ne dedi.

Örnekleme - kap, sunucu uygulamasına eşlenen ilk isteği aldığında bir sunucu uygulaması başlatılır (sunucu uygulamacığı <load-on-startup>öğeyle girişte yüklenecek şekilde yapılandırılmadığı sürece web.xml). Aynı örnek, sonraki istekleri sunmak için kullanılır.


3
Doğru. Ek düşünce: Her istek, bu tek Servlet örneğinde çalışacak yeni (veya geri dönüştürülmüş) bir iş parçacığı alır. Her Sunucu uygulamasının bir örneği ve muhtemelen çok sayıda iş parçacığı vardır (aynı anda birden fazla istek varsa).
Basil Bourque

13

Servlet Spesifikasyonu JSR-315 , hizmet (ve doGet, doPost, doPut vb.) Yöntemlerindeki (2.3.3.1 Çok İş Parçacığı Sorunları, Sayfa 9) web kapsayıcı davranışını açıkça tanımlar:

Bir sunucu uygulaması kabı, sunucu uygulamasının hizmet yöntemi aracılığıyla eşzamanlı istekler gönderebilir. İstekleri işlemek için Servlet Geliştiricisi, hizmet yönteminde birden çok iş parçacığıyla eşzamanlı işleme için yeterli koşulları sağlamalıdır.

Önerilmemesine rağmen, Geliştirici için bir alternatif, kabın hizmet yönteminde bir kerede yalnızca bir istek iş parçacığı olduğunu garanti etmesini gerektiren SingleThreadModel arabirimini uygulamaktır. Bir sunucu uygulaması kapsayıcısı, bir sunucu uygulamasındaki istekleri serileştirerek veya sunucu uygulaması örnekleri havuzunu koruyarak bu gereksinimi karşılayabilir. Sunucu uygulaması dağıtılabilir olarak işaretlenmiş bir Web uygulamasının parçasıysa, kapsayıcı, uygulamanın dağıtıldığı her JVM'de bir sunucu uygulaması örneği havuzu tutabilir.

SingleThreadModel arabirimini uygulamayan sunucu uygulamaları için, hizmet yöntemi (veya HttpServlet soyut sınıfının hizmet yöntemine gönderilen doGet veya doPost gibi yöntemler) eşitlenmiş anahtar sözcükle tanımlanmışsa, sunucu uygulaması kapsayıcısı örnek havuzu yaklaşımını kullanamaz , ancak istekleri seri hale getirmelidir. Geliştiricilerin performans üzerindeki zararlı etkileri nedeniyle bu durumda hizmet yöntemini (veya kendisine gönderilen yöntemleri) senkronize etmemeleri önemle tavsiye edilir


2
FYI, güncel Servlet spec (2015-01), JSR 340 tarafından tanımlanan 3.1'dir .
Basil Bourque


1
Çok temiz cevap! @Tharindu_DG
Tom Taylor

0

Yukarıdaki açıklamalardan da anlaşılacağı gibi, SingleThreadModel uygulanarak, sunucu uygulaması , sunucu uygulaması konteyneri tarafından iplik güvenliği sağlanabilir. Kapsayıcı uygulaması bunu 2 şekilde yapabilir:

1) İstekleri tek bir örneğe seri hale getirme - bu, service / doXXX yöntemlerini eşitlemede SingleThreadModel AMA UYGULAMAYAN bir sunucu uygulamasına benzer; VEYA

2) Bir sunucu havuzu oluşturmak - bu, sunucu uygulamasını barındıran ortamın kısıtlayıcı parametrelerine (bellek / CPU zamanı) karşı olduğu gibi, sunucu uygulamasının önyükleme / başlatma çabası / zamanı arasında daha iyi bir seçenek ve bir denge oluşturur.


-1

Hayır. Servletler İş parçacığı için güvenli değildir

Bu, aynı anda birden fazla iş parçacığına erişime izin verir

Eğer u iş parçacığı güvenli Servlet yapmak istiyorsanız., U gidebilir

Implement SingleThreadInterface(i) boş bir arayüz olan

yöntemleri

veya senkronizasyon yöntemlerine gidebiliriz

senkronize kullanarak tüm servis yöntemini senkronize olarak yapabiliriz

yöntemin önünde anahtar kelime

Misal::

public Synchronized class service(ServletRequest request,ServletResponse response)throws ServletException,IOException

veya senkronize blokta kodun blokunu koyabiliriz

Misal::

Synchronized(Object)

{

----Instructions-----

}

Senkronize bloğun tüm yöntemi yapmaktan daha iyi olduğunu hissediyorum

Senkronize

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.