Função / objetivo do ContextLoaderListener na primavera?

169

Estou aprendendo o Spring Framework, que está sendo usado no meu projeto. Encontrei a entrada ContextLoaderListener no meu arquivo web.xml . Mas não conseguiu descobrir exatamente como isso ajuda um desenvolvedor?

Na documentação oficial do ContextLoaderListener, ele diz que é para iniciar o WebApplicationContext . Em relação ao WebApplicationContext JavaDocs, diga:

Interface para fornecer configuração para um aplicativo Web.


Mas não consigo entender o que estou conseguindo com o ContextLoaderListener que inicializa internamente o WebApplicationContext ?

Pelo meu entendimento , ContextLoaderListener lê o arquivo de configuração do Spring (com o valor fornecido contra contextConfigLocation em web.xml ), analisa e carrega o bean singleton definido nesse arquivo de configuração. Da mesma forma, quando queremos carregar o protótipo de bean , usaremos o mesmo contexto de aplicativo da web para carregá-lo. Portanto, inicializamos o aplicativo da web com o ContextLoaderListener para ler / analisar / validar o arquivo de configuração antecipadamente e sempre que quisermos injetar dependência, podemos fazê-lo imediatamente sem demora. Esse entendimento está correto?

M Sach
fonte
1
Alguém pode me informar diferença entre RequestContextListener e ContextLoaderListener
VdeX

Respostas:

111

Sua compreensão está correta. O ApplicationContexté o lugar onde seus feijões Spring Live. O objetivo do ContextLoaderListeneré duplo:

  1. amarrar o ciclo de vida do ApplicationContextao ciclo de vida do ServletContexte

  2. para automatizar a criação do ApplicationContext, para que você não precise escrever código explícito para criá-lo - é uma função de conveniência.

Outra coisa conveniente sobre o ContextLoaderListeneré que ele cria um WebApplicationContexte WebApplicationContextfornece acesso ao ServletContextvia ServletContextAwarebeans e ao getServletContextmétodo.

sourcedelica
fonte
2
Eu tenho uma dúvida sobre o seu segundo ponto. Você disse que ServletContextListener fornece acesso a ServletContext. Mas, mesmo que o web.xml não possua ServletContextListener, o ServletContext pode ser acessado por meio do WebApplicationContext (o WebApplicationContext deve ser conectado automaticamente). Então, o que exatamente isso está relacionado ao ServletContext?
Sumit Desai
Isso cria o WebApplicationContext. Caso contrário, ele precisaria ser criado manualmente.
266133
se ContextLoaderListenerimplementar um método destroy para destruir todos os grãos quando os fecha contêiner web para baixo?
ASGs
sim - faz isso quando contextDestroyedé chamado. Veja os documentos da API.
sourcedelica
@sourcedelica Tenho uma dúvida depois de ler isso, verifiquei meus aplicativos web.xml. No meu arquivo xml, existem dois ouvintes ContextLoaderListenere DispatcherServlet. Então, eu acho que não há necessidade de ambos, é seguro remover o ContextLoaderListenermotivo pelo qual estou perguntando porque o aplicativo está ativo desde 7 a 8 meses. web.xml está aqui para sua referência.
quer
43

ContextLoaderListeneré opcional . Apenas para fazer um ponto aqui: você pode inicializar um aplicativo Spring sem nunca configurar ContextLoaderListener, apenas um mínimo básico web.xmlcom DispatcherServlet.

Aqui está o que seria:

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>

Crie um arquivo chamado dispatcher-servlet.xmle armazene-o em WEB-INF. Como mencionamos index.jspna lista de boas-vindas, adicione este arquivo em WEB-INF.

dispatcher-servlet.xml

No dispatcher-servlet.xmldefina seus beans:

<?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
fonte
2
Se for opcional, quando você deseja usá-lo? Parece que o Spring Security exige que ele use o DelegatingFilterProxy.
David
6
Você deve usá-lo quando desejar colocar seu arquivo Servlet em seu local personalizado ou com nome personalizado, em vez do nome padrão "[nome do servlet] -servlet.xml" e caminho em "Web-INF /"
Ramesh Karna
É uma boa ideia definir o bean no dispatcher-servlet.xml do que applicationContext.xml?
Chetan Gole
8
Geralmente, é melhor distribuir os beans refletindo as camadas da arquitetura do seu aplicativo. Os beans para a camada de apresentação (por exemplo, controladores mvc) podem estar em dispatcher-servlet.xml. Os grãos pertencentes à camada de serviço devem ser definidos applicationContext.xml. Não é uma regra estrita, mas é uma boa prática obter separação de preocupações.
Claudio Venturini
2
@Ramesh Karna Eu não acho que seja necessário para a mudança de nome e local. Eu acho que é necessário quando estamos inicializando vários servlets Dispatcher e ainda queremos que um contexto Raiz seja compartilhado por todo o próprio contexto DispaterServlets, então precisamos usar ContextLoaderListener.
Supernova
23

Para um aplicativo Spring simples, você não precisa definir ContextLoaderListenerno seu web.xml; você pode simplesmente colocar todos os seus arquivos de configuração do Spring em <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>

Para um aplicativo Spring mais complexo, em que você tenha várias definições DispatcherServletdefinidas, é possível ter os arquivos de configuração comuns do Spring que são compartilhados por todos os DispatcherServletdefinidos em 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>

Lembre-se de que ContextLoaderListenerexecuta o trabalho de inicialização real para o contexto do aplicativo raiz .

Achei que este artigo ajuda bastante: Spring MVC - Contexto do Aplicativo x Contexto do Aplicativo da Web

xli
fonte
o artigo compartilhado aqui realmente garante profunda compreensão dos conceitos
Priyank Thakkar
10

O blog " Objetivo do ContextLoaderListener - Spring MVC " fornece uma explicação muito boa.

Segundo ele, os contextos de aplicativos são hierárquicos e, portanto, o contexto de DispatcherSerlvet se torna filho do contexto de ContextLoaderListener. Por esse motivo, a tecnologia usada na camada do controlador (Struts ou Spring MVC) pode ser independente do contexto raiz criado ContextLoaderListener.

Dileepa
fonte
Obrigado por compartilhar isso camarada .. :)
Deepak Kumar
3

Quando você deseja colocar seu arquivo Servlet em seu local personalizado ou com um nome personalizado, em vez da convenção de nomenclatura padrão [servletname]-servlet.xmle do caminho Web-INF/, é possível usar ContextLoaderListener.

Dungeon_master
fonte
3

ContextLoaderListner é um ouvinte de Servlet que carrega todos os diferentes arquivos de configuração (configuração da camada de serviço, configuração da camada de persistência, etc.) no contexto de aplicativo de mola única.

Isso ajuda a dividir as configurações de primavera em vários arquivos XML.

Depois que os arquivos de contexto são carregados, o Spring cria um objeto WebApplicationContext com base na definição do bean e o armazena no ServletContext do seu aplicativo da web.

Prashant_M
fonte
3

insira a descrição da imagem aquiEsse ouvinte do Bootstrap deve iniciar e desligar o WebApplicationContext raiz do Spring . Como um aplicativo da Web pode ter vários servlet de despachante e cada um com seu próprio contexto de aplicativo contendo controladores, resolvedor de exibição, mapeamentos de manipuladores, etc. contexto do aplicativo criado pelos servlets do expedidor).

O segundo uso desse ouvinte é quando você deseja usar a segurança da primavera.

rulhaniam
fonte
3

Contextos raiz e filho Antes de ler mais, entenda que -

A primavera pode ter vários contextos ao mesmo tempo. Um deles será o contexto raiz e todos os outros contextos serão contextos filhos.

Todos os contextos filhos podem acessar os beans definidos no contexto raiz; mas o contrário não é verdade. O contexto raiz não pode acessar os beans de contextos filhos.

ApplicationContext:

applicationContext.xml é a configuração de contexto raiz para todos os aplicativos da web. O Spring carrega o arquivo applicationContext.xml e cria o ApplicationContext para todo o aplicativo. Haverá apenas um contexto de aplicativo por aplicativo da web. Se você não declarar explicitamente o nome do arquivo de configuração de contexto em web.xml usando o parâmetro contextConfigLocation, o Spring procurará o applicationContext.xml na pasta WEB-INF e lançará FileNotFoundException se não conseguir encontrar esse arquivo.

ContextLoaderListener Executa o trabalho de inicialização real para o contexto do aplicativo raiz. Lê um parâmetro de contexto "contextConfigLocation" e passa seu valor para a instância de contexto, analisando-o em caminhos de arquivos potencialmente múltiplos que podem ser separados por qualquer número de vírgulas e espaços, por exemplo, "WEB-INF / applicationContext1.xml, WEB-INF / applicationContext2.xml ". ContextLoaderListener é opcional. Apenas para fazer um ponto aqui: você pode inicializar um aplicativo Spring sem nunca configurar o ContextLoaderListener, apenas um web.xml mínimo básico com o DispatcherServlet.

DispatcherServlet DispatcherServlet é essencialmente um Servlet (estende HttpServlet) cujo objetivo principal é lidar com solicitações da Web recebidas que correspondem ao padrão de URL configurado. É necessário um URI de entrada e encontra a combinação certa de controlador e visualização. Portanto, é o controlador frontal.

Ao definir um DispatcherServlet na configuração de primavera, você fornece um arquivo XML com entradas de classes do controlador, exibe mapeamentos etc. usando o atributo contextConfigLocation.

WebApplicationContext Além do ApplicationContext, pode haver vários WebApplicationContext em um único aplicativo Web. Em palavras simples, cada DispatcherServlet associado a um único WebApplicationContext. O arquivo xxx-servlet.xml é específico ao DispatcherServlet e um aplicativo da Web pode ter mais de um DispatcherServlet configurado para manipular as solicitações. Em tais cenários, cada DispatcherServlet teria um xxx-servlet.xml separado configurado. Mas, applicationContext.xml será comum a todos os arquivos de configuração do servlet. Por padrão, o Spring carregará o arquivo chamado "xxx-servlet.xml" da pasta WEB-INF dos webapps, em que xxx é o nome do servlet em web.xml. Se você deseja alterar o nome desse arquivo ou alterar o local, adicione initi-param com contextConfigLocation como nome do parâmetro.

Comparação e relação entre eles:

ContextLoaderListener vs DispatcherServlet

ContextLoaderListener cria o contexto do aplicativo raiz. As entradas DispatcherServlet criam um contexto de aplicativo filho por entrada de servlet. Contextos filhos podem acessar beans definidos no contexto raiz. Os beans no contexto raiz não podem acessar os beans nos contextos filhos (diretamente). Todos os contextos são adicionados ao ServletContext. Você pode acessar o contexto raiz usando a classe WebApplicationContextUtils.

Depois de ler a documentação do Spring, a seguir está o entendimento:

a) Os contextos de aplicativos são hierárquicos e o WebApplicationContexts. Consulte a documentação aqui.

b) ContextLoaderListener cria um contexto de aplicativo da Web raiz para o aplicativo da Web e o coloca no ServletContext. Esse contexto pode ser usado para carregar e descarregar os beans gerenciados por mola, respectivamente, de qual tecnologia está sendo usada na camada do controlador (Struts ou Spring MVC).

c) DispatcherServlet cria seu próprio WebApplicationContext e os manipuladores / controladores / resolvedores de exibição são gerenciados por esse contexto.

d) Quando ContextLoaderListener é usado em conjunto com DispatcherServlet, um contexto de aplicativo da web raiz é criado primeiro como dito anteriormente e um contexto filho também é criado pelo DispatcherSerlvet e é anexado ao contexto do aplicativo raiz. Consulte a documentação aqui.

Quando trabalhamos com o Spring MVC e também usamos o Spring na camada de serviços, fornecemos dois contextos de aplicativos. O primeiro é configurado usando ContextLoaderListener e o outro com DispatcherServlet

Geralmente, você definirá todos os beans relacionados ao MVC (controlador e visualizações etc.) no contexto DispatcherServlet e todos os beans transversais, como segurança, transação, serviços etc. no contexto raiz por ContextLoaderListener.

Consulte isso para obter mais detalhes: https://siddharthnawani.blogspot.com/2019/10/contextloaderlistener-vs.html

Siddharth Nawani
fonte
2

Basicamente, você pode isolar o contexto do aplicativo raiz e o contexto do aplicativo Web usando ContextLoaderListner.

O arquivo de configuração mapeado com o parâmetro context se comportará como configuração de contexto do aplicativo raiz. E o arquivo de configuração mapeado com o servlet do dispatcher se comportará como o contexto do aplicativo da web.

Em qualquer aplicativo da Web, podemos ter vários servlets do dispatcher, portanto, múltiplos contextos de aplicativos da Web.

Porém, em qualquer aplicativo Web, podemos ter apenas um contexto de aplicativo raiz compartilhado com todos os contextos de aplicativo Web.

Devemos definir nossos serviços, entidades, aspectos etc. comuns no contexto do aplicativo raiz. E controladores, interceptadores etc. estão no contexto relevante de aplicativos da web.

Uma amostra web.xml é

<!-- 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> 

Aqui, a classe de configuração example.config.AppConfig pode ser usada para configurar serviços, entidades, aspectos etc. no contexto do aplicativo raiz que serão compartilhados com todos os outros contextos de aplicativos da Web (por exemplo, aqui temos duas classes de configuração do contexto de aplicativos da Web RestConfig e WebConfig)

PS: Aqui o ContextLoaderListener é completamente opcional. Se não mencionarmos ContextLoaderListener no web.xml aqui, o AppConfig não funcionará. Nesse caso, precisamos configurar todos os nossos serviços e entidades no WebConfig e Rest Config.

Anil Agrawal
fonte
1

Isso dará a você um ponto de conexão para colocar algum código que você deseja executar no tempo de implantação de aplicativos da web

Jigar Joshi
fonte
Jigar, na verdade, é isso que estou tentando descobrir. Qual é o recurso que a classe do carregador de contexto padrão fornece no momento da implantação?
M Sach
Alterando as propriedades de arquivos / XML e deixá-los ser recarregado no momento nanico sem reiniciar o servidor
vsingh
1

Classe ouvinte - ouve um evento (por exemplo, inicialização / desligamento do servidor)

ContextLoaderListener -

  1. Escuta durante a inicialização / desligamento do servidor
  2. Pega os arquivos de configuração do Spring como entrada e cria os beans conforme a configuração e os prepara (destrói o bean durante o desligamento)
  3. Os arquivos de configuração podem ser fornecidos assim em web.xml

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

No contexto da estrutura de primavera, o objetivo do ContextLoaderListener é carregar os outros beans em seu aplicativo, como os componentes da camada intermediária e da camada de dados que conduzem o backend do aplicativo.

Salahin Rocky
fonte
0

Sua compreensão está correta. Gostaria de saber por que você não vê nenhuma vantagem no ContextLoaderListener. Por exemplo, você precisa criar uma fábrica de sessões (para gerenciar o banco de dados). Esta operação pode demorar algum tempo, por isso é melhor fazê-lo na inicialização. Claro que você pode fazer isso com servlets init ou qualquer outra coisa, mas a vantagem da abordagem do Spring é que você faz a configuração sem escrever código.

evg
fonte
0

Se escrevermos web.xml sem ContextLoaderListener, não poderemos fornecer a documentação usando customAuthenticationProvider na segurança da primavera. Como DispatcherServelet é o contexto filho de ContextLoaderListener, customAuthenticationProvider é a parte de parentContext que é ContextLoaderListener. Portanto, o Contexto pai não pode ter as dependências do contexto filho. Portanto, é uma prática recomendada escrever spring-context.xml no contextparam em vez de gravá-lo no initparam.

SathishSakthi
fonte
0

Eu acredito que seu uso real ocorre quando você deseja ter mais de um arquivo de configuração ou você tem o arquivo xyz.xml em vez de applicationcontext.xml, por exemplo

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

Outra abordagem para ContextLoaderListener está usando ContextLoaderServlet como abaixo

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

user666
fonte