inicializar - Ayuda/explicación de la jerarquía de configuración del archivo Spring XML
spring configuracion (1)
Cuando comencé a aprender sobre Spring, las cosas se configuraron en el archivo applicationContext.xml. Luego, cuando comencé a leer libros específicamente en versiones más recientes de la primavera, todos hicieron la configuración en archivos XML separados, como myapp-servlet-xml, myapp-security.xml, myapp-service.xml, etc., por configurar un contextConfigLocation en el archivo web.xml. Entonces, por ejemplo, el código que he estado siguiendo junto con esto es como contextConfigLocation:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/myapp-servlet.xml
/WEB-INF/myapp-data.xml
</param-value>
</context-param>
De todos modos, recientemente me encontré con un problema de configuración (que la gente útil aquí en StackOverflow me ayudó a descubrir) que se debía a esta separación. No había ningún archivo applicationContext.xml para los ejemplos de estos libros y más adelante cuando traté de agregar escaneos automáticos y anotaciones a la aplicación, esto causó problemas. Traté de mover todo a applicationContext.xml y acabar con los otros archivos y eso resolvió el problema. Nada más cambió, simplemente puse todo en applicationContext.xml.
Por lo tanto, esto, junto con los comentarios de otros, me ha llevado a entender que incluso si no se crea una aplicaciónContext.xml, todavía se está utilizando y es el nivel superior de algún tipo de jerarquía de configuración. Espero que alguien más me explique cómo funciona todo esto, porque no he encontrado ninguna explicación en ningún lado.
Entonces, por ejemplo, si pongo cierto contexto: etiquetas de exploración de componentes en archivos de configuración que están debajo de applicationContext.xml, podría causar que ciertas clases no sean escaneadas. Cosas de esa naturaleza No entiendo la precedencia y lo que tiene que ir donde esté seguro de que se ha visto una aplicación amplia y demás. Si alguien puede explicarlo claramente o señalarme un recurso que lo explique, lo agradecería mucho, gracias. Espero que lo que estoy pidiendo tenga sentido.
No hay nada de especial en el archivo llamado "applicationContext.xml", excepto que es el nombre que Spring tiende a esperar como su archivo de configuración predeterminado. Usar un archivo llamado así o múltiples archivos llamados "dog.xml", "cat.xml" y "alien.xml" funcionarán exactamente de la misma manera. El problema que está teniendo proviene de tener múltiples ApplicationContexts en uso al mismo tiempo, no de tener múltiples archivos XML. Recientemente respondí un par de preguntas de personas que tuvieron problemas causados por no entender estos conceptos. Vea esas respuestas y vea qué preguntas aún tiene:
Declaración de Spring Bean en el contexto de los padres frente al contexto de los niños
Spring-MVC: ¿Qué son un "contexto" y un "espacio de nombres"?
Editar: en respuesta a su nueva pregunta:
Tenía una etiqueta
<context:component-scan base-package="com.myapp"/>
en mi servlet.xml.
Supongo que este archivo "servlet.xml" se llama como foo-servlet.xml
, donde el DispatcherServlet configurado en su web.xml se llama "foo", como
<servlet>
<servlet-name>foo</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
Por convención, cuando este DispatcherServlet comience, creará un nuevo ApplicationContext que está configurado por el archivo foo-servlet.xml
, derivado del servlet-name
del servlet-name
. Ahora, desde que coloca un context:component-scan
allí, escaneará recursivamente el paquete dado y creará frijoles para todas las clases anotadas. El paquete que le com.myapp
, com.myapp
, parece ser el paquete base para toda su aplicación, por lo que Spring creará beans de todas las clases anotadas en su aplicación, incluidos los de acceso a datos, en este ApplicationContext asociado a la aplicación. DispatcherServlet. Por lo general, este contexto solo debe tener material de capa de vista y beans que admitan directamente el DispatcherServlet, por lo que esto fue una configuración incorrecta.
En mi archivo data.xml, tenía beans fuente de datos y eso fue todo. No hay otros frijoles, todo lo demás fue auto-conectado y anotado.
Presumiblemente, este archivo "data.xml" es el que usted enumeró en contextConfigLocation
context-param. Suponiendo que también haya agregado el ContextLoaderListener a su web.xml
, como
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
luego ese archivo se usará para crear un segundo ApplicationContext: el contexto raíz. Eso es lo que hace este oyente. Tenga en cuenta que en realidad construye el contexto de todos los archivos listados en contextConfigLocation
, y si también incluyó su "servlet.xml" en esa lista, entonces ha cargado esa configuración dos veces: aquí en el contexto raíz y en el contexto asociado con DipatcherServlet. Esperemos que ahora vea cómo hay una división distinta entre los archivos de configuración XML y los ApplicationContexts que configuran. El mismo archivo XML se puede usar fácilmente para configurar dos contextos diferentes. Si hacerlo es correcto o no es otra cuestión. En este caso particular, no lo es.
El orden en el que describí estos dos contextos es en realidad al revés. Solo estaba siguiendo tu descripción de lo que hiciste. El ContextLoaderListener, al ser un ServletContextListener , siempre se ejecutará antes de que se inicie cualquier servlet. Esto significa que el contexto raíz se crea primero, y el otro contexto en segundo lugar. Esto es por diseño, de modo que cuando DispatcherServlet crea su contexto, puede agregar ese contexto como un elemento secundario del contexto raíz. Describí esta relación en esas otras publicaciones. El efecto más importante de esto es que los beans en el contexto raíz están disponibles para y a través del contexto del Servidor Dispatcher. Eso también se aplica a las relaciones de autoenlace. Esto es importante porque DispatcherServlet solo busca en su contexto asociado los beans que necesita, como las instancias de controlador. Sin embargo, sus controladores obviamente tienen que estar conectados con granos de soporte. Por lo tanto, tradicionalmente, los controladores viven en el contexto del Servidor Dispatcher, y los beans de soporte viven en el contexto raíz.
Luego traté de agregar @Transacational a mi bean de servicio y no persistió.
Para que @Transactional funcione, debe incluir la etiqueta <tx:annotation-driven/>
en la configuración de ApplicationContext donde vive el bean anotado. El truco está en descubrir la parte "donde vive". Los frijoles en un niño pueden anular los frijoles en un contexto principal. Por lo tanto, estoy adivinando aquí, si cargó todos sus beans en el contexto del DispatcherServlet como describí anteriormente, pero puso el <tx:annotation-driven/>
en el contexto raíz, podría tener un bean en el contexto raíz eso es correctamente transaccional, pero no es el que se utiliza porque el duplicado está "más cerca" del servlet en la jerarquía principal / secundaria, y el contexto en el que se encuentra no obtuvo una configuración <tx:annotation-driven/>
.
Cuando cambié el contexto de servlet: etiqueta component-scan para apuntar a com.myapp.web y luego agregué un contexto: etiqueta component-scan al archivo data.xml, todo funcionó.
Todavía depende un tanto de exactamente qué archivos de configuración incluiste en qué ApplicationContexts, pero al menos puedo decir que al hacer esto, eliminaste muchos beans del contexto del DispatcherServlet que causaban problemas. En particular, los beans @Transactional configurados correctamente en el contexto raíz ya no se verían sombreados por los beans en el contexto secundario y se inyectarían en los controladores, por lo que su persistencia funcionaría en ese momento.
Entonces ... lo principal es que tienes dos ApplicationContexts relacionados. Debe mantenerse al tanto de ese hecho y mantener el control de los granos en qué contexto.
¿Eso cubre todo?