Peran / Tujuan ContextLoaderListener di Musim Semi?

169

Saya belajar Spring Framework yang sedang digunakan dalam proyek saya. Saya menemukan entri ContextLoaderListener di file web.xml saya . Tetapi tidak dapat mengetahui bagaimana tepatnya hal itu membantu pengembang?

Dalam dokumentasi resmi ContextLoaderListener dikatakan mengatakan untuk memulai WebApplicationContext . Mengenai WebApplicationContext, JavaDocs mengatakan:

Antarmuka untuk memberikan konfigurasi untuk aplikasi web.


Tetapi saya tidak dapat memahami apa yang saya capai dengan ContextLoaderListener yang secara internal menginisialisasi WebApplicationContext ?

Sesuai pemahaman saya , ContextLoaderListener membaca file konfigurasi Spring (dengan nilai yang diberikan terhadap contextConfigLocation di web.xml ), mem- parsingnya dan memuat kacang tunggal yang didefinisikan dalam file konfigurasi tersebut. Demikian pula ketika kita ingin memuat kacang prototipe , kita akan menggunakan konteks aplikasi web yang sama untuk memuatnya. Jadi kami menginisialisasi aplikasi web dengan ContextLoaderListener sehingga kami membaca / parse / memvalidasi file konfigurasi terlebih dahulu dan setiap kali kami ingin menyuntikkan dependensi, kami dapat langsung melakukannya tanpa penundaan. Apakah pemahaman ini benar?

M Sach
sumber
1
adakah yang bisa memberi tahu saya perbedaan antara RequestContextListener dan ContextLoaderListener
VdeX

Jawaban:

111

Pemahaman Anda benar. Di ApplicationContextsinilah kacang Spring Anda hidup. Tujuannya ContextLoaderListeneradalah dua kali lipat:

  1. untuk mengikat siklus hidup ApplicationContextke siklus hidup ServletContextdan

  2. untuk mengotomatiskan pembuatan ApplicationContext, jadi Anda tidak perlu menulis kode eksplisit untuk membuatnya - ini adalah fungsi yang praktis.

Hal lain yang nyaman tentang itu ContextLoaderListeneradalah bahwa ia menciptakan WebApplicationContextdan WebApplicationContextmenyediakan akses ke kacang ServletContextmelalui ServletContextAwaredan getServletContextmetode.

sourcedelica
sumber
2
Saya ragu tentang poin kedua Anda. Anda mengatakan ServletContextListener menyediakan akses ke ServletContext. Tetapi, bahkan jika web.xml tidak memiliki ServletContextListener, ServletContext dapat diakses melalui WebApplicationContext (WebApplicationContext akan diautomatiskan). Jadi, apa sebenarnya yang berhubungan dengan ServletContext?
Sumit Desai
Ini menciptakan WebApplicationContext. Kalau tidak, harus dibuat secara manual.
sourcedelica
Apakah ContextLoaderListenermenerapkan metode penghancuran untuk menghancurkan semua kacang ketika wadah web dimatikan?
asgs
ya - ia melakukan itu ketika contextDestroyeddipanggil. Lihat dokumentasi API.
sourcedelica
@sourcedelica Saya punya satu keraguan setelah membaca ini saya telah memeriksa aplikasi saya web.xml. Di file xml saya ada dua pendengar ContextLoaderListenerdan DispatcherServlet. Jadi saya kira tidak perlu keduanya, apakah aman untuk menghapus ContextLoaderListenermengapa saya bertanya karena aplikasi hidup sejak 7-8 bulan. web.xml ada di sini untuk referensi Anda.
Amogh
43

ContextLoaderListeneradalah opsional . Hanya untuk membuat titik di sini: Anda dapat boot up aplikasi musim semi tanpa pernah mengkonfigurasi ContextLoaderListener, hanya dasar minimum web.xmldengan DispatcherServlet.

Ini akan terlihat seperti apa:

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns="http://java.sun.com/xml/ns/javaee" 
    xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" 
    xsi:schemaLocation="
        http://java.sun.com/xml/ns/javaee 
        http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" 
    id="WebApp_ID" 
    version="2.5">
  <display-name>Some Minimal Webapp</display-name>
  <welcome-file-list>   
    <welcome-file>index.jsp</welcome-file>    
  </welcome-file-list>

  <servlet>
    <servlet-name>dispatcher</servlet-name>
    <servlet-class>
      org.springframework.web.servlet.DispatcherServlet
    </servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
    <url-pattern>*.do</url-pattern>
  </servlet-mapping>
</web-app>

Buat file yang dipanggil dispatcher-servlet.xmldan simpan di bawah WEB-INF. Karena kami sebutkan index.jspdalam daftar selamat datang, tambahkan file ini di bawahWEB-INF .

dispatcher-servlet.xml

Di dispatcher-servlet.xmltentukan kacang Anda:

<?xml version="1.0" encoding="UTF-8"?>
<beans 
    xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd     
        http://www.springframework.org/schema/context     
        http://www.springframework.org/schema/context/spring-context.xsd">

    <bean id="bean1">
      ...
    </bean>
    <bean id="bean2">
      ...
    </bean>         

    <context:component-scan base-package="com.example" />
    <!-- Import your other configuration files too -->
    <import resource="other-configs.xml"/>
    <import resource="some-other-config.xml"/>

    <!-- View Resolver -->
    <bean 
        id="viewResolver" 
        class="org.springframework.web.servlet.view.UrlBasedViewResolver">
      <property 
          name="viewClass" 
          value="org.springframework.web.servlet.view.JstlView" />
      <property name="prefix" value="/WEB-INF/jsp/" />
      <property name="suffix" value=".jsp" />
    </bean>
</beans>
Vikram
sumber
2
Jika opsional, kapan Anda ingin menggunakannya? Tampaknya Spring Security mengharuskannya menggunakan DelegatingFilterProxy.
David
6
Anda harus menggunakannya saat ingin meletakkan file Servlet di lokasi khusus atau dengan nama khusus, alih-alih nama default "[servlet-name] -servlet.xml" dan lintasan di bawah "Web-INF /"
Ramesh Karna
Apakah ide yang baik untuk mendefinisikan kacang di dispatcher-servlet.xml daripada applicationContext.xml?
Chetan Gole
8
Biasanya lebih baik mendistribusikan kacang dengan memantulkan lapisan arsitektur aplikasi Anda. Kacang-kacangan untuk lapisan presentasi (misalnya pengontrol mvc) dapat dalam dispatcher-servlet.xml. Kacang yang termasuk dalam lapisan layanan harus didefinisikan applicationContext.xml. Itu bukan aturan yang ketat, tapi itu praktik yang baik untuk mencapai pemisahan perhatian.
Claudio Venturini
2
@ Ramesh Karna Saya tidak berpikir itu diperlukan untuk perubahan nama dan lokasi. Saya pikir ini diperlukan ketika kita menginisialisasi beberapa servlet Dispatcher dan masih ingin konteks Root untuk dibagikan oleh semua konteks DispaterServlets sendiri maka kita perlu menggunakan ContextLoaderListener.
supernova
23

Untuk aplikasi Musim Semi yang sederhana, Anda tidak perlu mendefinisikan ContextLoaderListenerdi web.xml; Anda bisa meletakkan semua file konfigurasi Spring Anda di <servlet>:

<servlet>
    <servlet-name>hello</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring/mvc-core-config.xml, classpath:spring/business-config.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

Untuk aplikasi Pegas yang lebih kompleks, di mana Anda memiliki banyak DispatcherServletdefinisi, Anda dapat memiliki file konfigurasi Pegas umum yang digunakan bersama oleh semua yang DispatcherServletdidefinisikan dalam ContextLoaderListener:

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:spring/common-config.xml</param-value>
</context-param>
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<servlet>
    <servlet-name>mvc1</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring/mvc1-config.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet>
    <servlet-name>mvc2</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring/mvc2-config.xmll</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

Hanya perlu diingat, ContextLoaderListenermelakukan pekerjaan inisialisasi aktual untuk root konteks aplikasi .

Saya menemukan artikel ini banyak membantu: Spring MVC - Konteks Aplikasi vs Konteks Aplikasi Web

xli
sumber
artikel yang dibagikan di sini benar-benar memastikan pemahaman yang mendalam tentang konsep-konsep
Priyank Thakkar
10

Blog, " Purpose of ContextLoaderListener - Spring MVC " memberikan penjelasan yang sangat bagus.

Menurutnya, Konteks Aplikasi adalah hierarki dan karenanya konteks DispatcherSerlvet menjadi anak konteks ContextLoaderListener. Karena itu, teknologi yang digunakan dalam lapisan pengontrol (Struts atau Spring MVC) dapat terlepas dari konteks akar yang dibuat ContextLoaderListener.

Dileepa
sumber
Terima kasih sudah berbagi sobat .. :)
Deepak Kumar
3

Ketika Anda ingin meletakkan file Servlet Anda di lokasi kustom Anda atau dengan nama kustom, daripada konvensi penamaan default [servletname]-servlet.xmldan jalur di bawah Web-INF/, maka Anda dapat menggunakan ContextLoaderListener.

Dungeon_master
sumber
3

ContextLoaderListner adalah pendengar Servlet yang memuat semua file konfigurasi yang berbeda (konfigurasi lapisan layanan, konfigurasi lapisan persistensi, dll.) Ke dalam konteks aplikasi pegas tunggal.

Ini membantu untuk membagi konfigurasi pegas di beberapa file XML.

Setelah file konteks dimuat, Spring membuat objek WebApplicationContext berdasarkan definisi bean dan menyimpannya dalam ServletContext aplikasi web Anda.

Prashant_M
sumber
3

masukkan deskripsi gambar di siniPendengar Bootstrap ini untuk memulai dan mematikan root Spring WebApplicationContext . Karena aplikasi web dapat memiliki beberapa servlet dispatcher dan masing-masing memiliki konteks aplikasi sendiri yang mengandung pengontrol, view resolver, pemetaan handler dll. Tetapi Anda mungkin ingin memiliki kacang layanan, kacang DAO dalam konteks aplikasi root dan ingin digunakan dalam semua konteks aplikasi anak ( konteks aplikasi yang dibuat oleh servlet operator).

Penggunaan kedua pendengar ini adalah saat Anda ingin menggunakan keamanan pegas.

Rulehaniam
sumber
3

Konteks root dan anak Sebelum membaca lebih lanjut, harap dipahami bahwa -

Musim semi dapat memiliki banyak konteks sekaligus. Salah satunya adalah konteks root, dan semua konteks lainnya adalah konteks anak.

Semua konteks anak dapat mengakses kacang yang didefinisikan dalam konteks root; tetapi kebalikannya tidak benar. Konteks root tidak dapat mengakses kacang konteks anak.

ApplicationContext:

applicationContext.xml adalah konfigurasi konteks root untuk setiap aplikasi web. Pegas memuat file applicationContext.xml dan membuat ApplicationContext untuk seluruh aplikasi. Hanya akan ada satu konteks aplikasi per aplikasi web. Jika Anda tidak secara eksplisit mendeklarasikan nama file konfigurasi konteks di web.xml menggunakan param contextConfigLocation, Spring akan mencari applicationContext.xml di bawah folder WEB-INF dan melempar FileNotFoundException jika tidak dapat menemukan file ini.

ContextLoaderListener Melakukan pekerjaan inisialisasi aktual untuk konteks aplikasi root. Membaca konteks-param "contextConfigLocation" dan meneruskan nilainya ke instance konteks, mem-parsingnya ke beberapa path file yang berpotensi yang dapat dipisahkan oleh sejumlah koma dan spasi, misalnya "WEB-INF / applicationContext1.xml, WEB-INF / applicationContext2.xml ”. ContextLoaderListener adalah opsional. Hanya untuk menjelaskan di sini: Anda dapat mem-boot aplikasi Musim Semi tanpa pernah mengkonfigurasi ContextLoaderListener, hanya web.xml minimum dasar dengan DispatcherServlet.

DispatcherServlet DispatcherServlet pada dasarnya adalah Servlet (ini meluas HttpServlet) yang tujuan utamanya adalah untuk menangani permintaan web masuk yang cocok dengan pola URL yang dikonfigurasi. Dibutuhkan URI yang masuk dan menemukan kombinasi yang tepat dari pengontrol dan tampilan. Jadi itu adalah pengontrol depan.

Ketika Anda menentukan DispatcherServlet dalam konfigurasi pegas, Anda memberikan file XML dengan entri kelas controller, melihat pemetaan dll menggunakan atribut contextConfigLocation.

WebApplicationContext Terlepas dari ApplicationContext, ada beberapa WebApplicationContext dalam satu aplikasi web. Dengan kata sederhana, setiap DispatcherServlet terkait dengan WebApplicationContext tunggal. file xxx-servlet.xml khusus untuk DispatcherServlet dan aplikasi web dapat memiliki lebih dari satu DispatcherServlet yang dikonfigurasi untuk menangani permintaan. Dalam skenario seperti itu, setiap DispatcherServlet akan memiliki xxx-servlet.xml yang terpisah dikonfigurasi. Tetapi, applicationContext.xml akan umum untuk semua file konfigurasi servlet. Pegas akan secara default memuat file bernama "xxx-servlet.xml" dari folder webapp WEB-INF Anda di mana xxx adalah nama servlet di web.xml. Jika Anda ingin mengubah nama nama file itu atau mengubah lokasi, tambahkan initi-param dengan contextConfigLocation sebagai nama param.

Perbandingan dan hubungan di antara mereka:

ContextLoaderListener vs DispatcherServlet

ContextLoaderListener membuat konteks aplikasi root. Entri DispatcherServlet membuat konteks aplikasi satu anak per entri servlet. Konteks anak dapat mengakses kacang yang didefinisikan dalam konteks root. Kacang dalam konteks root tidak dapat mengakses kacang dalam konteks anak (langsung). Semua konteks ditambahkan ke ServletContext. Anda dapat mengakses konteks root menggunakan kelas WebApplicationContextUtils.

Setelah membaca dokumentasi Spring, berikut ini adalah pengertiannya:

a) Aplikasi-Konteks adalah hierarkis dan begitu juga WebApplicationContexts. Lihat dokumentasi di sini.

b) ContextLoaderListener membuat root web-application-context untuk aplikasi web dan meletakkannya di ServletContext. Konteks ini dapat digunakan untuk memuat dan membongkar biji yang dikelola pegas terlepas dari teknologi apa yang digunakan dalam lapisan pengontrol (Struts atau Spring MVC).

c) DispatcherServlet membuat WebApplicationContext sendiri dan handler / controllers / view-resolvers dikelola oleh konteks ini.

d) Ketika ContextLoaderListener digunakan bersama-sama dengan DispatcherServlet, konteks web-aplikasi root dibuat terlebih dahulu seperti yang dikatakan sebelumnya dan konteks anak-anak juga dibuat oleh DispatcherSerlvet dan dilampirkan ke konteks aplikasi root. Lihat dokumentasi di sini.

Ketika kami bekerja dengan Spring MVC dan juga menggunakan Spring di lapisan layanan, kami menyediakan dua konteks aplikasi. Yang pertama dikonfigurasi menggunakan ContextLoaderListener dan yang lainnya dengan DispatcherServlet

Secara umum, Anda akan mendefinisikan semua kacang terkait MVC (controller dan tampilan dll) dalam konteks DispatcherServlet, dan semua kacang lintas-potong seperti keamanan, transaksi, layanan dll pada konteks akar oleh ContextLoaderListener.

Lihat ini untuk detail lebih lanjut: https://siddharthnawani.blogspot.com/2019/10/contextloaderlistener-vs.html

siddharth nawani
sumber
2

Pada dasarnya Anda dapat mengisolasi konteks aplikasi root dan konteks aplikasi web menggunakan ContextLoaderListner.

File config yang dipetakan dengan param konteks akan berperilaku sebagai konfigurasi konteks aplikasi root. Dan file konfigurasi yang dipetakan dengan servlet dispatcher akan berperilaku seperti konteks aplikasi web.

Dalam aplikasi web apa pun kami mungkin memiliki beberapa servlet operator, jadi beberapa konteks aplikasi web.

Tetapi dalam aplikasi web apa pun kita mungkin hanya memiliki satu konteks aplikasi root yang dibagikan dengan semua konteks aplikasi web.

Kita harus mendefinisikan layanan umum kita, entitas, aspek dll dalam konteks aplikasi root. Dan pengendali, pencegat dll dalam konteks aplikasi web yang relevan.

Sampel web.xml adalah

<!-- language: xml -->
<web-app>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <context-param>
        <param-name>contextClass</param-name>
        <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
    </context-param>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>example.config.AppConfig</param-value>
    </context-param>
    <servlet>
        <servlet-name>restEntryPoint</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextClass</param-name>
            <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
        </init-param>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>example.config.RestConfig</param-value>
        </init-param>       
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>restEntryPoint</servlet-name>
        <url-pattern>/rest/*</url-pattern>
    </servlet-mapping>
    <servlet>
        <servlet-name>webEntryPoint</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextClass</param-name>
            <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
        </init-param>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>example.config.WebConfig</param-value>
        </init-param>       
        <load-on-startup>1</load-on-startup>
    </servlet>  
    <servlet-mapping>
        <servlet-name>webEntryPoint</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

</web-app> 

Di sini config class example.config.AppConfig dapat digunakan untuk mengkonfigurasi layanan, entitas, aspek dll dalam konteks aplikasi root yang akan dibagikan dengan semua konteks aplikasi web lainnya (misalnya di sini kami memiliki dua kelas konfigurasi konteks aplikasi web, RestConfig dan WebConfig)

PS: Di sini ContextLoaderListener sepenuhnya opsional. Jika kami tidak akan menyebut ContextLoaderListener di web.xml di sini, AppConfig tidak akan berfungsi. Dalam hal ini kita perlu mengkonfigurasi semua layanan dan entitas kita di WebConfig dan Rest Config.

Anil Agrawal
sumber
1

Ini akan memberi Anda point of hook untuk menaruh beberapa kode yang Anda ingin dieksekusi pada waktu penyebaran aplikasi web

Jigar Joshi
sumber
Jigar, sebenarnya ini yang saya coba cari tahu. Apa fitur yang disediakan kelas loader konteks default pada waktu penempatan?
M Sach
Mengubah properti / file xml dan membiarkannya dimuat kembali pada waktu runtuh tanpa me-restart server
vsingh
1

Kelas pendengar - Mendengarkan acara (Misalnya .. Server startup / shutdown)

ContextLoaderListener -

  1. Mendengarkan saat server memulai / mematikan
  2. Mengambil file konfigurasi Spring sebagai input dan membuat kacang sesuai konfigurasi dan membuatnya siap (menghancurkan kacang saat shutdown)
  3. File konfigurasi dapat disediakan seperti ini di web.xml

    <param-name>contextConfigLocation</param-name>  
    <param-value>/WEB-INF/dispatcher-servlet.xml</param-value>  
bharanitharan
sumber
1

Dalam konteks kerangka pegas, tujuan ContextLoaderListener adalah untuk memuat kacang lainnya di aplikasi Anda seperti komponen tingkat menengah dan data tingkat yang mendorong bagian belakang aplikasi.

Salahin Rocky
sumber
0

Pemahaman Anda benar. Saya ingin tahu mengapa Anda tidak melihat kelebihan apa pun di ContextLoaderListener. Misalnya, Anda perlu membangun pabrik sesi (untuk mengelola database). Operasi ini bisa memakan waktu, jadi lebih baik melakukannya saat startup. Tentu saja Anda bisa melakukannya dengan init servlets atau yang lainnya, tetapi keuntungan dari pendekatan Spring adalah Anda membuat konfigurasi tanpa menulis kode.

evg
sumber
0

Jika kita menulis web.xml tanpa ContextLoaderListener maka kita tidak dapat memberikan informasi menggunakan customAuthenticationProvider dalam keamanan musim semi. Karena DispatcherServelet adalah konteks turunan dari ContextLoaderListener, customAuthenticationProvider adalah bagian dari parentContext yaitu ContextLoaderListener. Jadi Konteks induk tidak dapat memiliki dependensi konteks anak. Maka itu adalah praktik terbaik untuk menulis spring-context.xml dalam contextparam daripada menulisnya di initparam.

Sathish Sakthi
sumber
0

Saya percaya penggunaan sebenarnya datang ketika Anda ingin memiliki lebih dari satu file konfigurasi atau Anda memiliki file xyz.xml alih-alih applicationcontext.xml untuk misalnya

<context-param><param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/training-service.xml, /WEB-INF/training-data.xml</param-value> </context-param>

Pendekatan lain untuk ContextLoaderListener menggunakan ContextLoaderServlet seperti di bawah ini

<servlet> <servlet-name>context</servlet-name> <servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet>

pengguna666
sumber