Spring: parámetros de init de namespace vs contextConfigLocation en web.xml

Estoy leyendo la documentación de Spring MVC y tengo una pregunta con respecto a los parametros init. Estoy usando Spring 3.2 si es importante. ¿Cuál es la diferencia entre contextConfigLocation y namespace? ¿Está el contextConfigLocation solo para especificar las carpetas donde la clase de contexto puede encontrar una definición XML y el atributo de espacio de nombres para especificar el nombre del archivo?

 AppServlet org.springframework.web.servlet.DispatcherServlet  contextConfigLocation WEB-INF   namespace application-context.xml  1  

¿Es esto correcto? ¿Debería usar /WEB-INF/application-context.xml? ¿Y deberías especificar rutas?

TL; DR

Simplemente configure los valores de contextConfigLocation siempre que necesite especificar archivos de configuración personalizados. De esta manera, especificará los nombres de los archivos de configuración y sus ubicaciones.

El namespace es esencialmente una forma alternativa de indicar a la clase de cargador de contexto del contenedor Spring qué archivo de configuración usar. Nunca me molesto, solo uso contextConfigLocation cada vez que necesito configurar archivos de configuración personalizados.

Aquí hay un ejemplo de uno de mis proyectos Spring anteriores (algunas de las configuraciones se omitieron por razones de brevedad):

web.xml

   Spring Web Application example   org.springframework.web.context.ContextLoaderListener   contextConfigLocation  /WEB-INF/spring/jdbc/spring-jdbc.xml /WEB-INF/spring/security/spring-security-context.xml     spring-mvc org.springframework.web.servlet.DispatcherServlet  contextConfigLocation  /WEB-INF/spring/mvc/spring-mvc-servlet.xml     spring-mvc /admin/*   

Respuesta larga

OK, primero vamos a aclarar algunos momentos importantes. Hay dos tipos de contextos con los que nos enfrentamos:

  1. contexto raíz (principal)
  2. contexto de servlet individual (niño)

Cita de Spring Framework API (versión 3.2.2 en el momento de escribir esto) para WebApplicationContext (énfasis mío):

Al igual que los contextos generics de aplicaciones, los contextos de las aplicaciones web son jerárquicos. Existe un único contexto raíz por aplicación, mientras que cada servlet en la aplicación (incluido un servlet despachador en el marco MVC) tiene su propio contexto secundario .

También aquí: jerarquías de contexto :

Por ejemplo, si está desarrollando una aplicación web Spring MVC, normalmente tendrá un WebApplicationContext cargado a través del ContextLoaderListener de Spring y un WebApplicationContext hijo cargado a través del Spring’s DispatcherServlet . Esto da como resultado una jerarquía de contexto padre-hijo donde los componentes compartidos y la configuración de la infraestructura se declaran en el contexto raíz y se consumen en el contexto secundario mediante componentes específicos de la web.

Y aquí: 17.2 The DispatcherServlet :

Las instancias de ApplicationContext en Spring pueden tener un scope. En el marco de Web MVC, cada DispatcherServlet tiene su propio WebApplicationContext, que hereda todos los beans ya definidos en la raíz WebApplicationContext . Estos beans heredados pueden anularse en el ámbito específico del servlet, y puede definir nuevos beans específicos del ámbito local para una instancia de Servlet determinada.

Ahora veamos la configuración del contexto de la aplicación raíz . Aquí hay un ejemplo:
web.xml

    org.springframework.web.context.ContextLoaderListener   contextConfigLocation  /WEB-INF/spring/daoContext.xml /WEB-INF/spring/applicationContext.xml    

De la documentación oficial de Spring (énfasis mío):
5.14.4 Instanciación de ApplicationContext conveniente para aplicaciones web :

Puede crear instancias de ApplicationContext de forma declarativa utilizando, por ejemplo, un ContextLoader. Por supuesto, también puede crear instancias de ApplicationContext mediante progtwigción utilizando una de las implementaciones de ApplicationContext.

Puede registrar un ApplicationContext usando ContextLoaderListener (vea el ejemplo anterior)

El oyente inspecciona el parámetro contextConfigLocation. Si el parámetro no existe, el oyente utiliza /WEB-INF/applicationContext.xml como valor predeterminado . Cuando el parámetro existe, el oyente separa la cadena mediante el uso de delimitadores predefinidos (coma, punto y coma y espacios en blanco) y utiliza los valores como ubicaciones donde se buscarán los contextos de la aplicación. También se admiten patrones de ruta de estilo Ant. Los ejemplos son /WEB-INF/*Context.xml para todos los archivos con nombres que terminan en “Context.xml”, que residen en el directorio “WEB-INF”, y /WEB-INF/**/*Context.xml, para todos tales archivos en cualquier subdirectorio de “WEB-INF”.

Con bastante frecuencia, la configuración de Spring se divide en varios archivos. Es más lógico y conveniente, especialmente en los proyectos a gran escala. En nuestro ejemplo definimos explícitamente dos archivos XML de configuración: daoContext.xml y applicationContext.xml en la ubicación personalizada: /WEB-INF/spring/ . Nuevamente, si no hubiésemos definido contextConfigLocation , ContextLoaderListener intentaría ubicar el archivo de configuración predeterminado: /WEB-INF/applicationContext.xml .

NOTA:
El contexto raíz es opcional . También vea esta respuesta: https://stackoverflow.com/a/7451389/814702

Por lo tanto, si el archivo de configuración predeterminado /WEB-INF/applicationContext.xml no se ajusta a sus necesidades, utilice ContextLoaderListener junto con contextConfigLocation, donde puede definir archivos de configuración personalizados para definir el contexto de la aplicación raíz .

A continuación, veamos el contexto de la aplicación individual (niño) . De la documentación oficial de Spring (énfasis mío):
17.2 The DispatcherServlet

Tras la inicialización de un DispatcherServlet, Spring MVC busca un archivo llamado
[servlet-name] -servlet.xml en el directorio WEB-INF de su aplicación web y crea los beans definidos allí, anulando las definiciones de los beans definidos con el mismo nombre en el ámbito global.

Considere la siguiente configuración del Servlet DispatcherServlet (en el archivo web.xml):

   golfing org.springframework.web.servlet.DispatcherServlet 1   golfing /golfing/*   

Acerca de contextConfigLocation y namespace

De la documentación (énfasis mío):

Con la configuración de servlet anterior en su lugar, deberá tener un archivo llamado
/WEB-INF/golfing-servlet.xml en su aplicación; este archivo contendrá todos sus componentes específicos de Spring Web MVC (beans). Puede cambiar la ubicación exacta de este archivo de configuración a través de un parámetro de inicialización del servlet (consulte más detalles a continuación).

Puede personalizar instancias individuales de DispatcherServlet agregando parámetros de inicialización de Servlet (elementos init-param) a la statement del servlet en el archivo web.xml. Consulte la siguiente tabla para ver la lista de parámetros admitidos.

  • contextClass : Clase que implementa WebApplicationContext, que ejemplifica el contexto utilizado por este servlet. Por defecto, se utiliza XmlWebApplicationContext.

  • contextConfigLocation : Cadena que se pasa a la instancia de contexto (especificada por contextClass) para indicar dónde se pueden encontrar los contextos. La cadena consta potencialmente de múltiples cadenas (usando una coma como delimitador) para admitir contextos múltiples. En el caso de ubicaciones de contexto múltiples con beans que están definidos dos veces, la última ubicación tiene prioridad.

  • namespace : Namespace de WebApplicationContext. El valor predeterminado es [servlet-name] -servlet.

Ahora investiguemos la documentación API para las clases relacionadas. La clase DispatcherServlet extiende la clase abstracta FrameworkServlet . De los documentos de la API de FrameworkServlet (énfasis mío):

Pasa un servlet init-param de “contextConfigLocation” a la instancia de contexto, analizándolo en rutas de archivos potencialmente múltiples que pueden estar separadas por cualquier cantidad de comas y espacios, como
“test-servlet.xml, myServlet.xml”. Si no se especifica explícitamente, se supone que la implementación del contexto construirá una ubicación predeterminada desde el espacio de nombres del servlet .

El espacio de nombre predeterminado es “‘servlet-name’-servlet”, por ejemplo, “test-servlet” para un servlet-name “test” (que lleva a una ubicación predeterminada “/WEB-INF/test-servlet.xml” con XmlWebApplicationContext). El espacio de nombres también se puede establecer explícitamente a través del servlet init-param del “espacio de nombres” .

Este es el extracto del código fuente de FrameworkServlet :
FrameworkServlet.java

 .... /** * Suffix for WebApplicationContext namespaces. If a servlet of this class is * given the name "test" in a context, the namespace used by the servlet will * resolve to "test-servlet". */ public static final String DEFAULT_NAMESPACE_SUFFIX = "-servlet"; .... 

La clase de contexto predeterminada para FrameworkServlet es XmlWebApplicationContext . De los documentos de la API XmlWebApplicationContext (énfasis mío):

De forma predeterminada, la configuración se tomará de “/WEB-INF/applicationContext.xml” para el contexto raíz y “/WEB-INF/test-servlet.xml” para un contexto con el espacio de nombres “test-servlet” (como para una instancia de DispatcherServlet con el servlet-name “prueba”).

Los valores predeterminados de la ubicación de configuración pueden anularse mediante el parámetro de contexto “contextConfigLocation” de ContextLoader y servlet init-param de FrameworkServlet . Las ubicaciones de configuración pueden denotar archivos concretos como “/WEB-INF/context.xml” o patrones Ant-style como “/WEB-INF/*-context.xml” (ver PathMatcher javadoc para ver los detalles del patrón).

La contextConfigLocation ubicaciones de configuración predeterminadas mediante contextConfigLocation es la misma que en el ejemplo anterior para el contexto de la aplicación raíz.

En cuanto a anular el espacio de nombre predeterminado, hay algunos momentos importantes. Cuando establezca un nuevo espacio de nombres, no lo anteponga con /WEB-INF y no anexe .xml a él . La razón de esto puede descubrirse si buscamos en el archivo fuente de la clase XmlWebApplicationContext :
XmlWebApplicationContext.java

 ... /** Default config location for the root context */ public static final String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml"; /** Default prefix for building a config location for a namespace */ public static final String DEFAULT_CONFIG_LOCATION_PREFIX = "/WEB-INF/"; /** Default suffix for building a config location for a namespace */ public static final String DEFAULT_CONFIG_LOCATION_SUFFIX = ".xml"; ... /** * The default location for the root context is "/WEB-INF/applicationContext.xml", * and "/WEB-INF/test-servlet.xml" for a context with the namespace "test-servlet" * (like for a DispatcherServlet instance with the servlet-name "test"). */ @Override protected String[] getDefaultConfigLocations() { if (getNamespace() != null) { return new String[] {DEFAULT_CONFIG_LOCATION_PREFIX + getNamespace() + DEFAULT_CONFIG_LOCATION_SUFFIX}; } else { return new String[] {DEFAULT_CONFIG_LOCATION}; } } 

Como puede ver, el código fuente lo dice todo.

Ejemplo de especificar el espacio de nombres personalizado

web.xml

     spring-mvc org.springframework.web.servlet.DispatcherServlet  namespace spring/mvc/spring-mvc    spring-mvc /*   

El resultado es que, en lugar de usar el espacio de nombres predeterminado para construir la ruta al archivo de configuración, que de otro modo sería /WEB-INF/spring-mvc-servlet.xml , el contenedor buscará /WEB-INF/spring/mvc/spring-mvc.xml .

NOTA:
Las explicaciones anteriores relacionadas con la configuración del espacio de nombres personalizado son para la clase de contexto XmlWebApplicationContext predeterminada. Se puede especificar una clase alternativa, como AnnotationConfigWebApplicationContext , por lo que habrá algunos momentos especiales para eso.


CONCLUSIÓN

Es (en mi humilde opinión) mucho más fácil usar el parámetro contextConfigLocation para definir archivos de configuración personalizados, tanto para el contexto de la aplicación raíz como para los contextos individuales. La única diferencia es que para el contexto de la aplicación raíz, utiliza dentro del elemento , pero NO dentro de un servlet específico (tampoco olvide la clase listener). Y para el contexto secundario, usa nested dentro del elemento para cada servlet específico . Ver mis configuraciones de ejemplo ( web.xml ) al comienzo de esta publicación.

Fuentes adicionales (como si lo anterior no fuera suficiente :-)):

  • Documentación de referencia de Spring Framework
  • Contexto Spring MVC Cargando

También vea estas respuestas:

  • Diferencia entre applicationContext.xml y spring-servlet.xml en Spring
  • ¿Cuál es la diferencia entre ApplicationContext y WebApplicationContext en Spring MVC?
  • Spring-MVC: ¿Qué son un “contexto” y un “espacio de nombres”?

Creo que la respuesta de LuckyLuke tiene mucha información útil, pero no responde la pregunta. En particular, ¿cómo funcionan los parámetros “namespace” y “contextConfigLocation”?

El único lugar donde pude encontrar la respuesta concreta es el código fuente:

  • namespace parameter establece un espacio de nombre personalizado que se utilizará para crear una ubicación de configuración de contexto predeterminada
  • El parámetro contextConfigLocation establece la ubicación de configuración de contexto explícitamente, en lugar de confiar en la ubicación predeterminada creada desde el espacio de nombres

¿Cuál es la diferencia entre contextConfigLocation y namespace? contextConfigLocation se utiliza para especificar la ruta de los archivos de configuración de spring, lo que significa que se inicializarán. el espacio de nombres se usa para especificar la ruta y el nombre del DispatcherServlet de Spring MVC. el valor predeterminado es [Dispatcher_name]-servlet.xml , aquí hay un ejemplo:

  dispatcher org.springframework.web.servlet.DispatcherServlet  namespace config/spring-mvc  1  

Spring buscará un archivo que se utilizará como su configuración de /WEB-INF/config/spring-mvc.xml mediante la ruta de /WEB-INF/config/spring-mvc.xml .
¿Es contextConfigLocation solo para especificar las carpetas donde la clase de contexto puede encontrar una definición XML?

  contextConfigLocation /WEB-INF/config/app-*.xml  

El código anterior mostró que cuando la aplicación que inicia Spring carga todos los archivos cuyo nombre comienza con ‘app-‘ y termina con ‘.xml’ en el directorio WEB-INF / config.

¿Debería usar /WEB-INF/application-context.xml? ¿Y deberías especificar rutas?
A través del ejemplo anterior, podemos saber que al configurar Spring debemos especificar la ruta completa y el nombre genérico y cuando SpringMVC solo debemos especificar la ruta (si está ubicada en un directorio, no incluir el directorio WEB-INF) y el nombre (no incluye la extensión).
Espero ayudarte 🙂